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