Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dxranchormanager_openxr.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include "openxr/qopenxrhelpers_p.h"
7
8#include <QtQuick3DUtils/private/qssgassert_p.h>
9
10#include <QtGui/qquaternion.h>
11
12#include <QLoggingCategory>
13
14#if defined(Q_OS_ANDROID)
15# include <QtCore/private/qandroidextras_p.h>
16#endif
17
19
20Q_DECLARE_LOGGING_CATEGORY(lcQuick3DXr);
21
22//<uses-permission android:name="com.oculus.permission.USE_ANCHOR_API" />
23
24static const uint32_t MAX_PERSISTENT_SPACES = 100;
25
26static const char qssgXrRecognizedLabels[] = "TABLE,COUCH,FLOOR,CEILING,WALL_FACE,WINDOW_FRAME,DOOR_FRAME,STORAGE,BED,SCREEN,LAMP,PLANT,WALL_ART,OTHER";
27
28[[nodiscard]] static QQuick3DXrSpatialAnchor::Classification getLabelForString(const QString &label)
29{
30 if (label == QStringLiteral("TABLE"))
31 return QQuick3DXrSpatialAnchor::Classification::Table;
32 if (label == QStringLiteral("COUCH"))
33 return QQuick3DXrSpatialAnchor::Classification::Seat;
34 if (label == QStringLiteral("FLOOR"))
35 return QQuick3DXrSpatialAnchor::Classification::Floor;
36 if (label == QStringLiteral("CEILING"))
37 return QQuick3DXrSpatialAnchor::Classification::Ceiling;
38 if (label == QStringLiteral("WALL_FACE"))
39 return QQuick3DXrSpatialAnchor::Classification::Wall;
40 if (label == QStringLiteral("WINDOW_FRAME"))
41 return QQuick3DXrSpatialAnchor::Classification::Window;
42 if (label == QStringLiteral("DOOR_FRAME"))
43 return QQuick3DXrSpatialAnchor::Classification::Door;
44
45 return QQuick3DXrSpatialAnchor::Classification::Other;
46}
47
48
49QQuick3DXrAnchorManager::QQuick3DXrAnchorManager()
50{
51
52}
53
54QQuick3DXrAnchorManager::~QQuick3DXrAnchorManager()
55{
56
57}
58
60{
61 static QQuick3DXrAnchorManager instance;
62 return &instance;
63}
64
65void QQuick3DXrAnchorManager::initialize(XrInstance instance, XrSession session)
66{
67#if defined(Q_OS_ANDROID)
68 auto res = QtAndroidPrivate::requestPermission(QLatin1StringView("com.oculus.permission.USE_SCENE"));
69 res.waitForFinished();
70#endif
71
72 m_instance = instance;
73 m_session = session;
74
75 // Get the function pointers
76 OpenXRHelpers::resolveXrFunction(
77 m_instance,
78 "xrEnumerateSpaceSupportedComponentsFB",
79 (PFN_xrVoidFunction*)(&xrEnumerateSpaceSupportedComponentsFB));
80 OpenXRHelpers::resolveXrFunction(
81 m_instance,
82 "xrGetSpaceComponentStatusFB",
83 (PFN_xrVoidFunction*)(&xrGetSpaceComponentStatusFB));
84 OpenXRHelpers::resolveXrFunction(
85 m_instance,
86 "xrSetSpaceComponentStatusFB",
87 (PFN_xrVoidFunction*)(&xrSetSpaceComponentStatusFB));
88 OpenXRHelpers::resolveXrFunction(
89 m_instance,
90 "xrGetSpaceUuidFB",
91 (PFN_xrVoidFunction*)(&xrGetSpaceUuidFB));
92 OpenXRHelpers::resolveXrFunction(
93 m_instance,
94 "xrQuerySpacesFB",
95 (PFN_xrVoidFunction*)(&xrQuerySpacesFB));
96 OpenXRHelpers::resolveXrFunction(
97 m_instance,
98 "xrRetrieveSpaceQueryResultsFB",
99 (PFN_xrVoidFunction*)(&xrRetrieveSpaceQueryResultsFB));
100 OpenXRHelpers::resolveXrFunction(
101 m_instance,
102 "xrGetSpaceBoundingBox2DFB",
103 (PFN_xrVoidFunction*)(&xrGetSpaceBoundingBox2DFB));
104 OpenXRHelpers::resolveXrFunction(
105 m_instance,
106 "xrGetSpaceBoundingBox3DFB",
107 (PFN_xrVoidFunction*)(&xrGetSpaceBoundingBox3DFB));
108 OpenXRHelpers::resolveXrFunction(
109 m_instance,
110 "xrGetSpaceSemanticLabelsFB",
111 (PFN_xrVoidFunction*)(&xrGetSpaceSemanticLabelsFB));
112 OpenXRHelpers::resolveXrFunction(
113 m_instance,
114 "xrGetSpaceBoundary2DFB",
115 (PFN_xrVoidFunction*)(&xrGetSpaceBoundary2DFB));
116 OpenXRHelpers::resolveXrFunction(
117 m_instance,
118 "xrGetSpaceRoomLayoutFB",
119 (PFN_xrVoidFunction*)(&xrGetSpaceRoomLayoutFB));
120 OpenXRHelpers::resolveXrFunction(
121 m_instance,
122 "xrGetSpaceContainerFB",
123 (PFN_xrVoidFunction*)(&xrGetSpaceContainerFB));
124 OpenXRHelpers::resolveXrFunction(
125 m_instance,
126 "xrRequestSceneCaptureFB",
127 (PFN_xrVoidFunction*)(&xrRequestSceneCaptureFB));
128}
129
131{
132
133}
134
136{
137 return {
138 // XR_EXT_UUID_EXTENSION_NAME, // ### Crashes on Quest 3. Theoretically required for XR_FB_spatial_entity (would work anyway, but is a validation error)
139 XR_FB_SPATIAL_ENTITY_EXTENSION_NAME,
140 XR_FB_SPATIAL_ENTITY_QUERY_EXTENSION_NAME,
141 XR_FB_SPATIAL_ENTITY_STORAGE_EXTENSION_NAME,
142 XR_FB_SPATIAL_ENTITY_CONTAINER_EXTENSION_NAME,
143 XR_FB_SCENE_EXTENSION_NAME,
144#ifdef Q_OS_ANDROID // no scene capture with Simulator as of version 57
145 XR_FB_SCENE_CAPTURE_EXTENSION_NAME
146#endif
147 };
148}
149
150void QQuick3DXrAnchorManager::handleEvent(const XrEventDataBaseHeader *event)
151{
152 if (event->type == XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) {
153 qCDebug(lcQuick3DXr, "QQuick3DXrAnchorManager::handleEvent: received XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB");
154 const XrEventDataSpaceSetStatusCompleteFB* setStatusComplete = (const XrEventDataSpaceSetStatusCompleteFB*)(event);
155 if (setStatusComplete->result == XR_SUCCESS) {
156 if (setStatusComplete->componentType == XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB) {
157 addAnchor(setStatusComplete->space, setStatusComplete->uuid);
158 }
159 }
160 } else if (event->type == XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB) {
161 qCDebug(lcQuick3DXr, "QQuick3DXrAnchorManager::handleEvent: received XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB");
162 const XrEventDataSceneCaptureCompleteFB* captureResult = (const XrEventDataSceneCaptureCompleteFB*)(event);
163 if (captureResult->result == XR_SUCCESS) {
164 Q_EMIT sceneCaptureCompleted();
165 qCDebug(lcQuick3DXr,
166 "QQuick3DXrAnchorManager::handleEvent: Scene capture (ID = %llu) succeeded",
167 static_cast<long long unsigned int>(captureResult->requestId));
168 } else {
169 qCDebug(lcQuick3DXr,
170 "QQuick3DXrAnchorManager::handleEvent: Scene capture (ID = %llu) failed with an error %d",
171 static_cast<long long unsigned int>(captureResult->requestId),
172 captureResult->result);
173 }
174
175 } else if (event->type == XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) {
176 qCDebug(lcQuick3DXr, "QQuick3DXrAnchorManager::handleEvent: received XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB");
177 const XrEventDataSpaceQueryResultsAvailableFB* resultsAvailable = (const XrEventDataSpaceQueryResultsAvailableFB*)(event);
178
179 XrSpaceQueryResultsFB queryResults{};
180 queryResults.type = XR_TYPE_SPACE_QUERY_RESULTS_FB;
181 queryResults.resultCapacityInput = 0;
182 queryResults.resultCountOutput = 0;
183 queryResults.results = nullptr;
184
185 if (!checkXrResult(retrieveSpaceQueryResults(resultsAvailable->requestId, &queryResults))) {
186 qWarning("Failed to retrieve space query results");
187 return;
188 }
189
190 QVector<XrSpaceQueryResultFB> results(queryResults.resultCountOutput);
191 queryResults.resultCapacityInput = results.size();
192 queryResults.resultCountOutput = 0;
193 queryResults.results = results.data();
194
195 if (!checkXrResult(retrieveSpaceQueryResults(resultsAvailable->requestId, &queryResults))) {
196 qWarning("Failed to retrieve space query results");
197 return;
198 }
199
200 qCDebug(lcQuick3DXr, "retrieveSpaceQueryResults: num of results received: %d", queryResults.resultCountOutput);
201 for (const auto &result : results) {
202 if (isComponentSupported(result.space, XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB)) {
203 XrSpaceComponentStatusSetInfoFB request = {
204 XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB,
205 nullptr,
206 XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB,
207 true,
208 0
209 };
210 XrAsyncRequestIdFB requestId;
211 XrResult res = setSpaceComponentStatus(result.space, &request, &requestId);
212 if (res == XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB) {
213 addAnchor(result.space, result.uuid);
214 }
215 }
216 }
217 } else if (event->type == XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) {
218 qCDebug(lcQuick3DXr, "QQuick3DXrAnchorManager::handleEvent: received XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB");
219 }
220}
221
223{
224 XrAsyncRequestIdFB requestId;
225 XrSceneCaptureRequestInfoFB request{};
226 request.type = XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB;
227 request.requestByteCount = 0;
228 request.request = nullptr;
229 if (!checkXrResult(requestSceneCapture(&request, &requestId)))
230 qWarning("Failed to request scene capture");
231}
232
233bool QQuick3DXrAnchorManager::isComponentSupported(XrSpace space, XrSpaceComponentTypeFB type)
234{
235 uint32_t numComponents = 0;
236 if (!checkXrResult(enumerateSpaceSupportedComponents(space, 0, &numComponents, nullptr))) {
237 qWarning("Failed to enumerate supported space components");
238 return false;
239 }
240
241 QVector<XrSpaceComponentTypeFB> components(numComponents);
242 if (!checkXrResult(enumerateSpaceSupportedComponents(space, numComponents, &numComponents, components.data()))) {
243 qWarning("Failed to enumerate supported space components");
244 return false;
245 }
246
247 bool supported = false;
248 for (const auto &component : components) {
249 if (component == type) {
250 supported = true;
251 break;
252 }
253 }
254
255 return supported;
256}
257
258bool QQuick3DXrAnchorManager::isComponentEnabled(XrSpace space, XrSpaceComponentTypeFB type)
259{
260 XrSpaceComponentStatusFB status = {XR_TYPE_SPACE_COMPONENT_STATUS_FB, nullptr, 0, 0};
261 if (!checkXrResult(getSpaceComponentStatus(space, type, &status))) {
262 qWarning("Failed to get space component status");
263 return false;
264 }
265 return (status.enabled && !status.changePending);
266}
267
268bool QQuick3DXrAnchorManager::getBoundingBox2D(XrSpace space, QVector2D &offset, QVector2D &extent)
269{
270 if (isComponentEnabled(space, XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB)) {
271 // Get the 2D bounds
272 XrRect2Df boundingBox2D;
273 if (!checkXrResult(getSpaceBoundingBox2D(space, &boundingBox2D))) {
274 qWarning("Failed to get bounding box 2D for space");
275 return false;
276 }
277 offset = QVector2D(boundingBox2D.offset.x, boundingBox2D.offset.y);
278 extent = QVector2D(boundingBox2D.extent.width, boundingBox2D.extent.height);
279 return true;
280 }
281 return false;
282}
283
284bool QQuick3DXrAnchorManager::getBoundingBox3D(XrSpace space, QVector3D &offset, QVector3D &extent)
285{
286 if (isComponentEnabled(space, XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB)) {
287 // Get the 3D bounds
288 XrRect3DfFB boundingBox3D;
289 if (!checkXrResult(getSpaceBoundingBox3D(space, &boundingBox3D))) {
290 qWarning("Failed to get bounding box 3D for space");
291 return false;
292 }
293 offset = QVector3D(boundingBox3D.offset.x, boundingBox3D.offset.y, boundingBox3D.offset.z);
294 extent = QVector3D(boundingBox3D.extent.width, boundingBox3D.extent.height, boundingBox3D.extent.depth);
295 return true;
296 }
297
298 return false;
299}
300
302{
303 QVector2D extent2D;
304 QVector2D offset2D;
305
306 QVector3D extent3D;
307 QVector3D offset3D;
308
309 QSSG_ASSERT(space != XR_NULL_HANDLE, return false);
310
311 const bool m_has2DBounds = getBoundingBox2D(space, offset2D, extent2D);
312 const bool m_has3DBounds = getBoundingBox3D(space, offset3D, extent3D);
313 if (isComponentSupported(space, XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB) &&
314 isComponentEnabled(space, XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB)) {
315 // Get the space container UUIDs
316 anchor.setSpaceContainerUuids(collectSpaceContainerUuids(space));
317 } else if (isComponentSupported(space, XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB) &&
318 isComponentEnabled(space, XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB)) {
319 anchor.setRoomLayoutUuids(collectRoomLayoutUuids(space));
320 }
321
322 if (m_has2DBounds)
323 anchor.setBounds2D(offset2D, extent2D);
324 if (m_has3DBounds)
325 anchor.setBounds3D(offset3D, extent3D);
326
327 auto stringLabel = getSemanticLabels(space);
328 auto semanticLable = getLabelForString(stringLabel);
329
330 anchor.setClassification(semanticLable);
331 anchor.setClassificationString(stringLabel);
332
333 return true;
334}
335
336namespace {
337bool isValidUuid(const XrUuidEXT& uuid) {
338 // The best, and reasonable way we can say if a uuid is valid, is to check if it's not null.
339 // Anyting more then that is outside the scope of this function (There's no real way to check if a uuid is valid
340 // that makese sense here anyways).
341 return !QtQuick3DXr::isNullUuid(uuid.data);
342}
343
344QUuid fromXrUuidExt(XrUuidEXT uuid) {
345 return QUuid::fromBytes(uuid.data);
346}
347
348XrUuidEXT fromQUuid(QUuid uuid) {
349 XrUuidEXT xrUuid;
350 auto bytes = uuid.toBytes();
351 memcpy(xrUuid.data, bytes.data, XR_UUID_SIZE_EXT);
352 return xrUuid;
353}
354
355}
356
358{
359 XrRoomLayoutFB roomLayout{};
360 roomLayout.type = XR_TYPE_ROOM_LAYOUT_FB;
361 QVector<XrUuidEXT> wallUuids;
362 QSet<QUuid> uuidSet;
363
364 // First call
365 if (!checkXrResult(getSpaceRoomLayout(space, &roomLayout))) {
366 qWarning("Failed to get room layout");
367 return uuidSet;
368 }
369
370 // If wallUuidCountOutput == 0, no walls in the component. The UUIDs of the ceiling and floor
371 // has been returned if available
372 if (roomLayout.wallUuidCountOutput != 0) {
373 // Second call
374 wallUuids.resize(roomLayout.wallUuidCountOutput);
375 roomLayout.wallUuidCapacityInput = wallUuids.size();
376 roomLayout.wallUuids = wallUuids.data();
377 if (!checkXrResult(getSpaceRoomLayout(space, &roomLayout))) {
378 qWarning("Failed to get room layout");
379 return uuidSet;
380 }
381 }
382 if (isValidUuid(roomLayout.floorUuid))
383 uuidSet.insert(fromXrUuidExt(roomLayout.floorUuid));
384 if (isValidUuid(roomLayout.ceilingUuid))
385 uuidSet.insert(fromXrUuidExt(roomLayout.ceilingUuid));
386 for (uint32_t i = 0; i < roomLayout.wallUuidCountOutput; i++)
387 uuidSet.insert(fromXrUuidExt(roomLayout.wallUuids[i]));
388 return uuidSet;
389}
390
392{
393 XrSpaceContainerFB spaceContainer{};
394 spaceContainer.type = XR_TYPE_SPACE_CONTAINER_FB;
395 QSet<QUuid> uuidSet;
396 // First call
397 if (!checkXrResult(getSpaceContainer(space, &spaceContainer))) {
398 qWarning("Failed to get container");
399 return uuidSet;
400 }
401 if (spaceContainer.uuidCountOutput != 0) {
402 // Second call
403 QVector<XrUuidEXT> uuids(spaceContainer.uuidCountOutput);
404 spaceContainer.uuidCapacityInput = uuids.size();
405 spaceContainer.uuids = uuids.data();
406 if (!checkXrResult(getSpaceContainer(space, &spaceContainer))) {
407 qWarning("Failed to get container");
408 return uuidSet;
409 }
410
411 for (uint32_t i = 0; i < spaceContainer.uuidCountOutput; i++)
412 uuidSet.insert(fromXrUuidExt(spaceContainer.uuids[i]));
413 }
414
415 return uuidSet;
416}
417
419 const XrSemanticLabelsSupportInfoFB semanticLabelsSupportInfo = {
420 XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB,
421 nullptr,
422 XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB | XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB,
424 };
425
426 XrSemanticLabelsFB labels{};
427 labels.type = XR_TYPE_SEMANTIC_LABELS_FB;
428 labels.next = &semanticLabelsSupportInfo;
429
430 if (!isComponentEnabled(space, XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB))
431 return QString();
432
433 // First call.
434 if (!checkXrResult(getSpaceSemanticLabels(space, &labels))) {
435 qWarning("Failed to get semantic labels");
436 return {};
437 }
438 // Second call
439 QByteArray labelData(labels.bufferCountOutput, Qt::Uninitialized);
440 labels.bufferCapacityInput = labelData.size();
441 labels.buffer = labelData.data();
442 if (!checkXrResult(getSpaceSemanticLabels(space, &labels))) {
443 qWarning("Failed to get semantic labels");
444 return {};
445 }
446
447 return QString::fromLocal8Bit(labelData);
448}
449
451 XrSpaceQueryInfoFB queryInfo = {
452 XR_TYPE_SPACE_QUERY_INFO_FB,
453 nullptr,
454 XR_SPACE_QUERY_ACTION_LOAD_FB,
456 0,
457 nullptr,
458 nullptr};
459
460 XrAsyncRequestIdFB requestId;
461 return checkXrResult(querySpaces((XrSpaceQueryInfoBaseHeaderFB*)&queryInfo, &requestId));
462}
463
465{
466 return m_anchors;
467}
468
470{
471 return m_anchors.count();
472}
473
474void QQuick3DXrAnchorManager::updateAnchors(XrTime predictedDisplayTime, XrSpace appSpace)
475{
476 // basically for each anchor, we need to call xrLocateSpace
477 for (auto &anchor : m_anchors) {
478 XrSpaceLocation spaceLocation{};
479 spaceLocation.type = XR_TYPE_SPACE_LOCATION;
480 XrResult res = xrLocateSpace(QtQuick3DXr::fromXrSpaceId<XrSpace>(anchor->space()), appSpace, predictedDisplayTime, &spaceLocation);
481 if (XR_UNQUALIFIED_SUCCESS(res)) {
482 if ((spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 &&
483 (spaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0) {
484
485 // Update transform
486 anchor->setPosition(QVector3D(spaceLocation.pose.position.x,
487 spaceLocation.pose.position.y,
488 spaceLocation.pose.position.z) * 100.0f);
489 anchor->setRotation(QQuaternion(spaceLocation.pose.orientation.w,
490 spaceLocation.pose.orientation.x,
491 spaceLocation.pose.orientation.y,
492 spaceLocation.pose.orientation.z));
493 }
494 }
495 }
496}
497
498bool QQuick3DXrAnchorManager::queryAllAnchorsWithSpecificComponentEnabled(const XrSpaceComponentTypeFB componentType) {
499 XrSpaceStorageLocationFilterInfoFB storageLocationFilterInfo = {
500 XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB,
501 nullptr,
502 XR_SPACE_STORAGE_LOCATION_LOCAL_FB
503 };
504
505 XrSpaceComponentFilterInfoFB componentFilterInfo = {
506 XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB,
507 &storageLocationFilterInfo,
508 componentType
509 };
510
511 XrSpaceQueryInfoFB queryInfo = {
512 XR_TYPE_SPACE_QUERY_INFO_FB,
513 nullptr,
514 XR_SPACE_QUERY_ACTION_LOAD_FB,
516 0,
517 (XrSpaceFilterInfoBaseHeaderFB*)&componentFilterInfo,
518 nullptr
519 };
520
521 XrAsyncRequestIdFB requestId;
522 if (!checkXrResult(querySpaces((XrSpaceQueryInfoBaseHeaderFB*)&queryInfo, &requestId))) {
523 qWarning("Failed to query spaces");
524 return false;
525 }
526 return true;
527}
528
529bool QQuick3DXrAnchorManager::queryAnchorsByUuids(const QSet<QUuid>& uuidSet) {
530 if (uuidSet.isEmpty())
531 return false;
532
533 QVector<XrUuidEXT> uuidsToQuery;
534
535 for (const auto &uuid : uuidSet) {
536 XrUuidEXT xrUuid = fromQUuid(uuid);
537 uuidsToQuery.append(xrUuid);
538 }
539
540 XrSpaceStorageLocationFilterInfoFB storageLocationFilterInfo = {
541 XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB,
542 nullptr,
543 XR_SPACE_STORAGE_LOCATION_LOCAL_FB
544 };
545
546 XrSpaceUuidFilterInfoFB uuidFilterInfo = {
547 XR_TYPE_SPACE_UUID_FILTER_INFO_FB,
548 &storageLocationFilterInfo,
549 (uint32_t)uuidsToQuery.size(),
550 uuidsToQuery.data()
551 };
552
553 XrSpaceQueryInfoFB queryInfo = {
554 XR_TYPE_SPACE_QUERY_INFO_FB,
555 nullptr,
556 XR_SPACE_QUERY_ACTION_LOAD_FB,
558 0,
559 (XrSpaceFilterInfoBaseHeaderFB*)&uuidFilterInfo,
560 nullptr
561 };
562
563 XrAsyncRequestIdFB requestId;
564 if (!checkXrResult(querySpaces((XrSpaceQueryInfoBaseHeaderFB*)&queryInfo, &requestId))) {
565 qWarning("Failed to query spaces");
566 return false;
567 }
568 return true;
569}
570
571void QQuick3DXrAnchorManager::addAnchor(XrSpace space, XrUuidEXT uuid)
572{
573 auto quuid = fromXrUuidExt(uuid);
574 // Check if we already have this anchor
575 if (m_anchorsByUuid.contains(quuid))
576 return;
577
578 QQuick3DXrSpatialAnchor *anchor = new QQuick3DXrSpatialAnchor(QtQuick3DXr::toXrSpaceId(space), quuid, this);
579 setupSpatialAnchor(space, *anchor);
580 m_anchorsByUuid.insert(quuid, anchor);
581 m_anchors.append(anchor);
582 Q_EMIT anchorAdded(anchor);
583}
584
585
586XrResult QQuick3DXrAnchorManager::enumerateSpaceSupportedComponents(XrSpace space, uint32_t componentTypeCapacityInput, uint32_t *componentTypeCountOutput, XrSpaceComponentTypeFB *componentTypes)
587{
588 return OpenXRHelpers::safeCall(xrEnumerateSpaceSupportedComponentsFB, space, componentTypeCapacityInput, componentTypeCountOutput, componentTypes);
589}
590
591XrResult QQuick3DXrAnchorManager::getSpaceComponentStatus(XrSpace space, XrSpaceComponentTypeFB componentType, XrSpaceComponentStatusFB *status)
592{
593 return OpenXRHelpers::safeCall(xrGetSpaceComponentStatusFB, space, componentType, status);
594}
595
596XrResult QQuick3DXrAnchorManager::setSpaceComponentStatus(XrSpace space, const XrSpaceComponentStatusSetInfoFB *info, XrAsyncRequestIdFB *requestId)
597{
598 return OpenXRHelpers::safeCall(xrSetSpaceComponentStatusFB, space, info, requestId);
599}
600
601XrResult QQuick3DXrAnchorManager::getSpaceUuid(XrSpace space, XrUuidEXT *uuid)
602{
603 return OpenXRHelpers::safeCall(xrGetSpaceUuidFB, space, uuid);
604}
605
606XrResult QQuick3DXrAnchorManager::querySpaces(const XrSpaceQueryInfoBaseHeaderFB *info, XrAsyncRequestIdFB *requestId)
607{
608 return OpenXRHelpers::safeCall(xrQuerySpacesFB, m_session, info, requestId);
609}
610
611XrResult QQuick3DXrAnchorManager::retrieveSpaceQueryResults(XrAsyncRequestIdFB requestId, XrSpaceQueryResultsFB *results)
612{
613 return OpenXRHelpers::safeCall(xrRetrieveSpaceQueryResultsFB, m_session, requestId, results);
614}
615
616XrResult QQuick3DXrAnchorManager::getSpaceBoundingBox2D(XrSpace space, XrRect2Df *boundingBox2DOutput)
617{
618 return OpenXRHelpers::safeCall(xrGetSpaceBoundingBox2DFB, m_session, space, boundingBox2DOutput);
619}
620
621XrResult QQuick3DXrAnchorManager::getSpaceBoundingBox3D(XrSpace space, XrRect3DfFB *boundingBox3DOutput)
622{
623 return OpenXRHelpers::safeCall(xrGetSpaceBoundingBox3DFB, m_session, space, boundingBox3DOutput);
624}
625
626XrResult QQuick3DXrAnchorManager::getSpaceSemanticLabels(XrSpace space, XrSemanticLabelsFB *semanticLabelsOutput)
627{
628 return OpenXRHelpers::safeCall(xrGetSpaceSemanticLabelsFB, m_session, space, semanticLabelsOutput);
629}
630
631XrResult QQuick3DXrAnchorManager::getSpaceBoundary2D(XrSpace space, XrBoundary2DFB *boundary2DOutput)
632{
633 return OpenXRHelpers::safeCall(xrGetSpaceBoundary2DFB, m_session, space, boundary2DOutput);
634}
635
636XrResult QQuick3DXrAnchorManager::getSpaceRoomLayout(XrSpace space, XrRoomLayoutFB *roomLayoutOutput)
637{
638 return OpenXRHelpers::safeCall(xrGetSpaceRoomLayoutFB, m_session, space, roomLayoutOutput);
639}
640
641XrResult QQuick3DXrAnchorManager::getSpaceContainer(XrSpace space, XrSpaceContainerFB *spaceContainerOutput)
642{
643 return OpenXRHelpers::safeCall(xrGetSpaceContainerFB, m_session, space, spaceContainerOutput);
644}
645
646XrResult QQuick3DXrAnchorManager::requestSceneCapture(const XrSceneCaptureRequestInfoFB *info, XrAsyncRequestIdFB *requestId)
647{
648 return OpenXRHelpers::safeCall(xrRequestSceneCaptureFB, m_session, info, requestId);
649}
650
651bool QQuick3DXrAnchorManager::checkXrResult(const XrResult &result)
652{
653 return OpenXRHelpers::checkXrResult(result, m_instance);
654}
655
656QT_END_NAMESPACE
QList< const char * > requiredExtensions() const
bool getBoundingBox2D(XrSpace space, QVector2D &offset, QVector2D &extent)
const QList< QQuick3DXrSpatialAnchor * > & anchors() const
bool isComponentEnabled(XrSpace space, XrSpaceComponentTypeFB type)
bool getBoundingBox3D(XrSpace space, QVector3D &offset, QVector3D &extent)
void updateAnchors(XrTime predictedDisplayTime, XrSpace appSpace)
void handleEvent(const XrEventDataBaseHeader *event)
bool isComponentSupported(XrSpace space, XrSpaceComponentTypeFB type)
bool setupSpatialAnchor(XrSpace space, QQuick3DXrSpatialAnchor &anchor)
void initialize(XrInstance instance, XrSession session)
QSet< QUuid > collectRoomLayoutUuids(XrSpace space)
QString getSemanticLabels(const XrSpace space)
QSet< QUuid > collectSpaceContainerUuids(XrSpace space)
static const uint32_t MAX_PERSISTENT_SPACES
static const char qssgXrRecognizedLabels[]
static QQuick3DXrSpatialAnchor::Classification getLabelForString(const QString &label)