Merge pull request #107391 from BastiaanOlij/openxr_spatial_entities_ext

OpenXR: Add support for spatial entities extension
This commit is contained in:
Thaddeus Crews 2025-09-28 10:07:49 -05:00
commit 8d8041bd4d
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
54 changed files with 7550 additions and 17 deletions

View file

@ -3466,6 +3466,44 @@
If [code]true[/code] we enable the render model extension if available. If [code]true[/code] we enable the render model extension if available.
[b]Note:[/b] This relates to the core OpenXR render model extension and has no relation to any vendor render model extensions. [b]Note:[/b] This relates to the core OpenXR render model extension and has no relation to any vendor render model extensions.
</member> </member>
<member name="xr/openxr/extensions/spatial_entity/april_tag_dict" type="int" setter="" getter="" default="&quot;3&quot;">
The April Tag marker types the built-in marker tracking is set to recognize (if April Tag marker tracking is available and enabled).
</member>
<member name="xr/openxr/extensions/spatial_entity/aruco_dict" type="int" setter="" getter="" default="&quot;15&quot;">
The ArUco marker types the built-in marker tracking is set to recognize (if ArUco marker tracking is available and enabled).
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_builtin_anchor_detection" type="bool" setter="" getter="" default="false">
If [code]true[/code], we enable the built-in logic for handling anchors. Godot will query (persistent) anchors and manage [OpenXRAnchorTracker] instances for you. If disabled you'll need to create your own spatial and persistence context and perform your own discovery queries.
[b]Note:[/b] This functionality requires that spatial anchors are supported and enabled.
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_builtin_marker_tracking" type="bool" setter="" getter="" default="false">
If [code]true[/code], we enable the built-in logic for handling marker tracking. Godot will query markers and manage [OpenXRMarkerTracker] instances for you. If disabled you'll need to create your own spatial context and perform your own discovery queries.
[b]Note:[/b] This functionality requires that marker tracking is supported and enabled.
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_builtin_plane_detection" type="bool" setter="" getter="" default="false">
If [code]true[/code], we enable the built-in logic for handling plane detection. Godot will query detected planes (walls, floors, ceilings, etc.) and manage [OpenXRPlaneTracker] instances for you. If disabled you'll need to create your own spatial context and perform your own discovery queries.
[b]Note:[/b] This functionality requires that plane tracking is supported and enabled.
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_marker_tracking" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the marker tracking extension is requested. If supported, you will be able to query information about markers detected by the XR runtime, e.g. QR codes, aruca markers and april tags.
[b]Note:[/b] This requires that the OpenXR spatial entities and marker tracking extensions are supported by the XR runtime. If not supported this setting will be ignored. [member xr/openxr/extensions/spatial_entity/enabled] must be enabled for this setting to be used.
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_persistent_anchors" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the persistent anchors extension is requested. If supported, you will be able to store spatial anchors and they will be restored on application startup.
[b]Note:[/b] This requires that the OpenXR spatial entities, spatial anchors, and spatial persistence extensions are supported by the XR runtime. If not supported this setting will be ignored. [member xr/openxr/extensions/spatial_entity/enabled] and [member xr/openxr/extensions/spatial_entity/enable_spatial_anchors] must be enabled for this setting to be used.
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_plane_tracking" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the plane tracking extension is requested. If supported, you will be able to query information about planes detected by the XR runtime, e.g. walls, floors, etc.
[b]Note:[/b] This requires that the OpenXR spatial entities and plane tracking extensions are supported by the XR runtime. If not supported this setting will be ignored. [member xr/openxr/extensions/spatial_entity/enabled] must be enabled for this setting to be used.
</member>
<member name="xr/openxr/extensions/spatial_entity/enable_spatial_anchors" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the spatial anchors extension is requested. If supported, you will be able to register anchor locations in the real world that the XR runtime will adjust as needed and/or potentially share with other headsets.
[b]Note:[/b] This requires that the OpenXR spatial entities and spatial anchors extensions are supported by the XR runtime. If not supported this setting will be ignored. [member xr/openxr/extensions/spatial_entity/enabled] must be enabled for this setting to be used.
</member>
<member name="xr/openxr/extensions/spatial_entity/enabled" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the spatial entity extension is requested. If supported, you will be able to access spatial information about the real environment around you. What information is available is dependent on additional extensions.
[b]Note:[/b] This requires that the OpenXR spatial entities extension is supported by the XR runtime. If not supported this setting will be ignored.
</member>
<member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;"> <member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;">
Specify whether OpenXR should be configured for an HMD or a hand held device. Specify whether OpenXR should be configured for an HMD or a hand held device.
</member> </member>

View file

@ -2805,6 +2805,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_unobstructed_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_unobstructed_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_controller_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_controller_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false); GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enabled", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_spatial_anchors", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_persistent_anchors", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_builtin_anchor_detection", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_plane_tracking", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_builtin_plane_detection", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_marker_tracking", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_builtin_marker_tracking", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/spatial_entity/aruco_dict", PROPERTY_HINT_ENUM, "4x4 50 IDs,4x4 100 IDs,4x4 250 IDs,4x4 1000 IDs,5x5 50 IDs,5x5 100 IDs,5x5 250 IDs,5x5 1000 IDs,6x6 50 IDs,6x6 100 IDs,6x6 250 IDs,6x6 1000 IDs,7x7 50 IDs,7x7 100 IDs,7x7 250 IDs,7x7 1000 IDs"), "15");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/spatial_entity/april_tag_dict", PROPERTY_HINT_ENUM, "4x4H5,5x5H9,6x6H10,6x6H11"), "3");
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/eye_gaze_interaction", false); GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/render_model", false); GLOBAL_DEF_BASIC("xr/openxr/extensions/render_model", false);

View file

@ -43,6 +43,36 @@ def get_doc_classes():
"OpenXRRenderModelExtension", "OpenXRRenderModelExtension",
"OpenXRRenderModel", "OpenXRRenderModel",
"OpenXRRenderModelManager", "OpenXRRenderModelManager",
"OpenXRStructureBase",
"OpenXRSpatialEntityExtension",
"OpenXRSpatialEntityTracker",
"OpenXRAnchorTracker",
"OpenXRPlaneTracker",
"OpenXRMarkerTracker",
"OpenXRSpatialCapabilityConfigurationBaseHeader",
"OpenXRSpatialCapabilityConfigurationAnchor",
"OpenXRSpatialCapabilityConfigurationQrCode",
"OpenXRSpatialCapabilityConfigurationMicroQrCode",
"OpenXRSpatialCapabilityConfigurationAruco",
"OpenXRSpatialCapabilityConfigurationAprilTag",
"OpenXRSpatialContextPersistenceConfig",
"OpenXRSpatialCapabilityConfigurationPlaneTracking",
"OpenXRSpatialComponentData",
"OpenXRSpatialComponentBounded2DList",
"OpenXRSpatialComponentBounded3DList",
"OpenXRSpatialComponentParentList",
"OpenXRSpatialComponentMesh2DList",
"OpenXRSpatialComponentMesh3DList",
"OpenXRSpatialComponentPlaneAlignmentList",
"OpenXRSpatialComponentPolygon2DList",
"OpenXRSpatialComponentPlaneSemanticLabelList",
"OpenXRSpatialComponentMarkerList",
"OpenXRSpatialQueryResultData",
"OpenXRSpatialComponentAnchorList",
"OpenXRSpatialComponentPersistenceList",
"OpenXRSpatialAnchorCapability",
"OpenXRSpatialPlaneTrackingCapability",
"OpenXRSpatialMarkerTrackingCapability",
] ]

View file

@ -140,7 +140,7 @@
<method name="get_system_id"> <method name="get_system_id">
<return type="int" /> <return type="int" />
<description> <description>
Returns the id of the system, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemId.html]XrSystemId[/url] cast to an integer. Returns the ID of the system, which is an [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemId.html]XrSystemId[/url] cast to an integer.
</description> </description>
</method> </method>
<method name="insert_debug_label"> <method name="insert_debug_label">

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRAnchorTracker" inherits="OpenXRSpatialEntityTracker" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Positional tracker for our spatial entity anchor extension.
</brief_description>
<description>
Positional tracker for our OpenXR spatial entity anchor extension, it tracks a user defined location in real space and maps it to our virtual space.
</description>
<tutorials>
</tutorials>
<methods>
<method name="has_uuid" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if a non-zero UUID is set.
</description>
</method>
</methods>
<members>
<member name="uuid" type="String" setter="set_uuid" getter="get_uuid" default="&quot;&quot;">
The UUID provided for persistent anchors.
</member>
</members>
<signals>
<signal name="uuid_changed">
<description>
Emitted when the UUID for this anchor was changed.
</description>
</signal>
</signals>
</class>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRMarkerTracker" inherits="OpenXRSpatialEntityTracker" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Spatial entity tracker for our spatial entity marker tracking extension.
</brief_description>
<description>
Spatial entity tracker for our OpenXR spatial entity marker tracking extension. These trackers identify entities in our real space detected by a visual marker such as a QRCode or Aruco code, and map their location to our virtual space.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_marker_data" qualifiers="const">
<return type="Variant" />
<description>
Returns the marker data for this marker. This can return a [String] or [PackedByteArray]. Only applicable to QR Code based markers.
</description>
</method>
<method name="set_marker_data">
<return type="void" />
<param index="0" name="marker_data" type="Variant" />
<description>
Sets the marker data for this marker.
[b]Note:[/b] This should only be set by marker discovery logic.
</description>
</method>
</methods>
<members>
<member name="bounds_size" type="Vector2" setter="set_bounds_size" getter="get_bounds_size" default="Vector2(0, 0)">
The bounds size for this marker.
</member>
<member name="marker_id" type="int" setter="set_marker_id" getter="get_marker_id" default="0">
The marker ID for this marker, this is only returned for Aruco and April Tag markers. Call [method get_marker_data] for QRCode markers.
</member>
<member name="marker_type" type="int" setter="set_marker_type" getter="get_marker_type" enum="OpenXRSpatialComponentMarkerList.MarkerType" default="0">
The type of marker.
</member>
</members>
</class>

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRPlaneTracker" inherits="OpenXRSpatialEntityTracker" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Spatial entity tracker for our spatial entity plane tracking extension.
</brief_description>
<description>
Spatial entity tracker for our OpenXR spatial entity plane tracking extension. These trackers identify entities in our real space such as walls, floors, tables, etc. and map their location to our virtual space.
</description>
<tutorials>
</tutorials>
<methods>
<method name="clear_mesh_data">
<return type="void" />
<description>
Clears the mesh data for this tracker. You should only call this if you are handling your own discovery logic.
</description>
</method>
<method name="get_mesh">
<return type="Mesh" />
<description>
Gets a mesh created from either the mesh data or from our bounding size for this plane.
</description>
</method>
<method name="get_mesh_offset" qualifiers="const">
<return type="Transform3D" />
<description>
Gets the transform by which to offset the mesh and collision shape from our pose to display these correctly.
</description>
</method>
<method name="get_shape">
<return type="Shape3D" />
<param index="0" name="thickness" type="float" default="0.01" />
<description>
Gets a collision shape built either from the mesh data or from our bounding size for this plane.
</description>
</method>
<method name="set_mesh_data">
<return type="void" />
<param index="0" name="origin" type="Transform3D" />
<param index="1" name="vertices" type="PackedVector2Array" />
<param index="2" name="indices" type="PackedInt32Array" default="PackedInt32Array()" />
<description>
Sets the mesh data for this plane. You should only call this if you are handling your own discovery logic.
</description>
</method>
</methods>
<members>
<member name="bounds_size" type="Vector2" setter="set_bounds_size" getter="get_bounds_size" default="Vector2(0, 0)">
The bounding size of the plane. This is a 2D size.
</member>
<member name="plane_alignment" type="int" setter="set_plane_alignment" getter="get_plane_alignment" enum="OpenXRSpatialComponentPlaneAlignmentList.PlaneAlignment" default="0">
The main alignment in space of this plane.
</member>
<member name="plane_label" type="String" setter="set_plane_label" getter="get_plane_label" default="&quot;&quot;">
The semantic label for this plane.
</member>
</members>
<signals>
<signal name="mesh_changed">
<description>
Emitted when our mesh data has changed the mesh instance and collision needs to be updated.
</description>
</signal>
</signals>
</class>

View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialAnchorCapability" inherits="OpenXRExtensionWrapper" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Implementation for handling spatial entity anchor logic.
</brief_description>
<description>
This is an internal class that handles the OpenXR anchor spatial entity extension.
</description>
<tutorials>
</tutorials>
<methods>
<method name="create_new_anchor">
<return type="OpenXRAnchorTracker" />
<param index="0" name="transform" type="Transform3D" />
<param index="1" name="spatial_context" type="RID" default="RID()" />
<description>
Creates a new anchor that will be tracked by the XR runtime. The [param transform] should be a transform in the local space of your [XROrigin3D] node. If [param spatial_context] is not specified the default will be used, this requires [member ProjectSettings.xr/openxr/extensions/spatial_entity/enable_builtin_anchor_detection] to be set. The returned tracker will track the location in case our reference space changes.
</description>
</method>
<method name="create_persistence_context">
<return type="OpenXRFutureResult" />
<param index="0" name="scope" type="int" enum="OpenXRSpatialAnchorCapability.PersistenceScope" />
<param index="1" name="user_callback" type="Callable" default="Callable()" />
<description>
Creates a new persistence context for storing persistent data.
[b]Note:[/b] This is an asynchronous method and returns an [OpenXRFutureResult] object with which to track the status, discarding this object will not cancel the creation process. On success [param user_callback] will be called if specified. The result value for this function is the [RID] for our persistence context.
</description>
</method>
<method name="free_persistence_context">
<return type="void" />
<param index="0" name="persistence_context" type="RID" />
<description>
Frees a persistence context previously created with [method create_persistence_context].
</description>
</method>
<method name="get_persistence_context_handle" qualifiers="const">
<return type="int" />
<param index="0" name="persistence_context" type="RID" />
<description>
Returns the internal handle for this persistence context.
[b]Note:[/b] For GDExtension implementations.
</description>
</method>
<method name="is_persistence_scope_supported">
<return type="bool" />
<param index="0" name="scope" type="int" enum="OpenXRSpatialAnchorCapability.PersistenceScope" />
<description>
Returns [code]true[/code] if this persistence scope is supported by our spatial anchor capability.
[b]Note:[/b] Only valid after an OpenXR instance has been created.
</description>
</method>
<method name="is_spatial_anchor_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if spatial anchors are supported by the hardware. Only returns a valid value after OpenXR has been initialized.
</description>
</method>
<method name="is_spatial_persistence_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if persistent spatial anchors are supported by the hardware. Only returns a valid value after OpenXR has been initialized.
</description>
</method>
<method name="persist_anchor">
<return type="OpenXRFutureResult" />
<param index="0" name="anchor_tracker" type="OpenXRAnchorTracker" />
<param index="1" name="persistence_context" type="RID" default="RID()" />
<param index="2" name="user_callback" type="Callable" default="Callable()" />
<description>
Changes this anchor into a persistent anchor. This means its location will be stored on the device and the anchor will be restored the next time your application starts. If [param persistence_context] is not specified the default will be used, this requires [member ProjectSettings.xr/openxr/extensions/spatial_entity/enable_builtin_anchor_detection] to be set.
[b]Note:[/b] This is an asynchronous method and returns an [OpenXRFutureResult] object with which to track the status, discarding this object will not cancel the creation process. On success [param user_callback] will be called if specified. The result value for this function is a boolean which will be set to [code]true[/code] on successful completion.
</description>
</method>
<method name="remove_anchor">
<return type="void" />
<param index="0" name="anchor_tracker" type="OpenXRAnchorTracker" />
<description>
Remove an anchor previously created with [method create_new_anchor]. If this anchor was persistent you must first call [method unpersist_anchor] and await its callback.
</description>
</method>
<method name="unpersist_anchor">
<return type="OpenXRFutureResult" />
<param index="0" name="anchor_tracker" type="OpenXRAnchorTracker" />
<param index="1" name="persistence_context" type="RID" default="RID()" />
<param index="2" name="user_callback" type="Callable" default="Callable()" />
<description>
Removes the persistent data from this anchor. The runtime will not recreate the anchor when your application restarts. If [param persistence_context] is not specified the default will be used, this requires [member ProjectSettings.xr/openxr/extensions/spatial_entity/enabled] to be set.
[b]Note:[/b] This is an asynchronous method and returns an [OpenXRFutureResult] object with which to track the status, discarding this object will not cancel the creation process. On success [param user_callback] will be called if specified. The result value for this function is a boolean which will be set to [code]true[/code] on successful completion.
</description>
</method>
</methods>
<constants>
<constant name="PERSISTENCE_SCOPE_SYSTEM_MANAGED" value="1" enum="PersistenceScope">
Provides the application with read-only access (i.e. application cannot modify this scope) to spatial entities persisted and managed by the system. The application can use the UUID in the persistence component for this scope to correlate entities across spatial contexts and device reboots.
</constant>
<constant name="PERSISTENCE_SCOPE_LOCAL_ANCHORS" value="1000781000" enum="PersistenceScope">
Persistence operations and data access is limited to spatial anchors, on the same device, for the same user and same app (using [method persist_anchor] and [method unpersist_anchor] functions)
</constant>
</constants>
</class>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationAnchor" inherits="OpenXRSpatialCapabilityConfigurationBaseHeader" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for spatial anchors.
</brief_description>
<description>
Configuration header for spatial anchors. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] to create a spatial context with spatial anchor capabilities.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_enabled_components" qualifiers="const">
<return type="PackedInt64Array" />
<description>
Returns the components enabled by this configuration.
[b]Note:[/b] Only valid after this configuration was used to create a spatial context.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationAprilTag" inherits="OpenXRSpatialCapabilityConfigurationBaseHeader" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for April tag markers.
</brief_description>
<description>
Configuration header for April tag markers. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] to create a spatial context that can detect April tags.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_enabled_components" qualifiers="const">
<return type="PackedInt64Array" />
<description>
Returns the components enabled by this configuration.
[b]Note:[/b] Only valid after this configuration was used to create a spatial context.
</description>
</method>
</methods>
<members>
<member name="april_dict" type="int" setter="set_april_dict" getter="get_april_dict" enum="OpenXRSpatialCapabilityConfigurationAprilTag.AprilTagDict" default="4">
Dictionary to use to decode April tags.
[b]Note:[/b] Must be set before using this configuration to create a spatial context.
</member>
</members>
<constants>
<constant name="APRIL_TAG_DICT_16H5" value="1" enum="AprilTagDict">
4 by 4 bits, minimum Hamming distance between any two codes = 5, 30 codes.
</constant>
<constant name="APRIL_TAG_DICT_25H9" value="2" enum="AprilTagDict">
5 by 5 bits, minimum Hamming distance between any two codes = 9, 35 codes.
</constant>
<constant name="APRIL_TAG_DICT_36H10" value="3" enum="AprilTagDict">
6 by 6 bits, minimum Hamming distance between any two codes = 10, 2320 codes.
</constant>
<constant name="APRIL_TAG_DICT_36H11" value="4" enum="AprilTagDict">
6 by 6 bits, minimum Hamming distance between any two codes = 11, 587 codes.
</constant>
</constants>
</class>

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationAruco" inherits="OpenXRSpatialCapabilityConfigurationBaseHeader" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for Aruco markers.
</brief_description>
<description>
Configuration header for Aruco markers. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] to create a spatial context that can detect Aruco markers.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_enabled_components" qualifiers="const">
<return type="PackedInt64Array" />
<description>
Returns the components enabled by this configuration.
[b]Note:[/b] Only valid after this configuration was used to create a spatial context.
</description>
</method>
</methods>
<members>
<member name="aruco_dict" type="int" setter="set_aruco_dict" getter="get_aruco_dict" enum="OpenXRSpatialCapabilityConfigurationAruco.ArucoDict" default="16">
Dictionary to use to decode Aruco markers.
[b]Note:[/b] Must be set before using this configuration to create a spatial context.
</member>
</members>
<constants>
<constant name="ARUCO_DICT_4X4_50" value="1" enum="ArucoDict">
4 by 4 pixel Aruco marker dictionary with 50 IDs.
</constant>
<constant name="ARUCO_DICT_4X4_100" value="2" enum="ArucoDict">
4 by 4 pixel Aruco marker dictionary with 100 IDs.
</constant>
<constant name="ARUCO_DICT_4X4_250" value="3" enum="ArucoDict">
4 by 4 pixel Aruco marker dictionary with 250 IDs.
</constant>
<constant name="ARUCO_DICT_4X4_1000" value="4" enum="ArucoDict">
4 by 4 pixel Aruco marker dictionary with 1000 IDs.
</constant>
<constant name="ARUCO_DICT_5X5_50" value="5" enum="ArucoDict">
5 by 5 pixel Aruco marker dictionary with 50 IDs.
</constant>
<constant name="ARUCO_DICT_5X5_100" value="6" enum="ArucoDict">
5 by 5 pixel Aruco marker dictionary with 100 IDs.
</constant>
<constant name="ARUCO_DICT_5X5_250" value="7" enum="ArucoDict">
5 by 5 pixel Aruco marker dictionary with 250 IDs.
</constant>
<constant name="ARUCO_DICT_5X5_1000" value="8" enum="ArucoDict">
5 by 5 pixel Aruco marker dictionary with 1000 IDs.
</constant>
<constant name="ARUCO_DICT_6X6_50" value="9" enum="ArucoDict">
6 by 6 pixel Aruco marker dictionary with 50 IDs.
</constant>
<constant name="ARUCO_DICT_6X6_100" value="10" enum="ArucoDict">
6 by 6 pixel Aruco marker dictionary with 100 IDs.
</constant>
<constant name="ARUCO_DICT_6X6_250" value="11" enum="ArucoDict">
6 by 6 pixel Aruco marker dictionary with 250 IDs.
</constant>
<constant name="ARUCO_DICT_6X6_1000" value="12" enum="ArucoDict">
6 by 6 pixel Aruco marker dictionary with 1000 IDs.
</constant>
<constant name="ARUCO_DICT_7X7_50" value="13" enum="ArucoDict">
7 by 7 pixel Aruco marker dictionary with 50 IDs.
</constant>
<constant name="ARUCO_DICT_7X7_100" value="14" enum="ArucoDict">
7 by 7 pixel Aruco marker dictionary with 100 IDs.
</constant>
<constant name="ARUCO_DICT_7X7_250" value="15" enum="ArucoDict">
7 by 7 pixel Aruco marker dictionary with 250 IDs.
</constant>
<constant name="ARUCO_DICT_7X7_1000" value="16" enum="ArucoDict">
7 by 7 pixel Aruco marker dictionary with 1000 IDs.
</constant>
</constants>
</class>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationBaseHeader" inherits="RefCounted" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Wrapper base class for OpenXR Spatial Capability Configuration headers.
</brief_description>
<description>
Wrapper base class for OpenXR Spatial Capability Configuration headers. This class needs to be implemented for each capability configuration structure usable within OpenXR's spatial entities system.
</description>
<tutorials>
</tutorials>
<methods>
<method name="_get_configuration" qualifiers="virtual">
<return type="int" />
<description>
Return a pointer (encoded as an [code]int64_t[/code]) to a struct holding the spatial capability configuration data. The memory for this struct should remain accessible as long as this object remains instantiated.
</description>
</method>
<method name="_has_valid_configuration" qualifiers="virtual const">
<return type="bool" />
<description>
Return [code]true[/code] if this object contains a valid configuration that can be retrieved when calling [method _get_configuration].
</description>
</method>
<method name="has_valid_configuration" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if this object contains a valid configuration that can be used when calling [method OpenXRSpatialEntityExtension.create_spatial_context].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationMicroQrCode" inherits="OpenXRSpatialCapabilityConfigurationBaseHeader" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for QR code markers.
</brief_description>
<description>
Configuration header for QR code markers. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] to create a spatial context that can detect QR code markers.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_enabled_components" qualifiers="const">
<return type="PackedInt64Array" />
<description>
Returns the components enabled by this configuration.
[b]Note:[/b] Only valid after this configuration was used to create a spatial context.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationPlaneTracking" inherits="OpenXRSpatialCapabilityConfigurationBaseHeader" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for plane tracking.
</brief_description>
<description>
Configuration header for plane tracking. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] to create a spatial context with plane tracking capabilities.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_enabled_components" qualifiers="const">
<return type="PackedInt64Array" />
<description>
Returns the components enabled by this configuration.
[b]Note:[/b] Only valid after this configuration was used to create a spatial context.
</description>
</method>
<method name="supports_labels">
<return type="bool" />
<description>
Returns [code]true[/code] if we support the plane semantic label component (only valid after the OpenXR session has started). You can query these using the [OpenXRSpatialComponentPlaneSemanticLabelList] data object.
</description>
</method>
<method name="supports_mesh_2d">
<return type="bool" />
<description>
Returns [code]true[/code] if we support the mesh 2D component (only valid after the OpenXR session has started). You can query these using the [OpenXRSpatialComponentMesh2DList] data object.
</description>
</method>
<method name="supports_polygons">
<return type="bool" />
<description>
Returns [code]true[/code] if we support the polygon 2D component (only valid after the OpenXR session has started). You can query these using the [OpenXRSpatialComponentPolygon2DList] data object.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialCapabilityConfigurationQrCode" inherits="OpenXRSpatialCapabilityConfigurationBaseHeader" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for micro QR code markers.
</brief_description>
<description>
Configuration header for micro QR code markers. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] to create a spatial context that can detect micro QR code markers.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_enabled_components" qualifiers="const">
<return type="PackedInt64Array" />
<description>
Returns the components enabled by this configuration.
[b]Note:[/b] Only valid after this configuration was used to create a spatial context.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentAnchorList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries anchor result data.
</brief_description>
<description>
Object for storing the queries anchor result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_entity_pose" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="index" type="int" />
<description>
Returns the transform for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentBounded2DList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries bounded2d result data.
</brief_description>
<description>
Object for storing the queries 2D bounding rectangle result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_center_pose" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="index" type="int" />
<description>
Returns the center of our bounding rectangle for the entity at this [param index].
</description>
</method>
<method name="get_size" qualifiers="const">
<return type="Vector2" />
<param index="0" name="index" type="int" />
<description>
Returns the size of our bounding rectangle for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentBounded3DList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries bounded3d result data.
</brief_description>
<description>
Object for storing the queries 3d bounding box result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_center_pose" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="index" type="int" />
<description>
Returns the center of our bounding box for the entity at this [param index].
</description>
</method>
<method name="get_size" qualifiers="const">
<return type="Vector3" />
<param index="0" name="index" type="int" />
<description>
Returns the size of our bounding box for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentData" inherits="RefCounted" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing OpenXR spatial entity component data.
</brief_description>
<description>
Object for storing OpenXR spatial entity component data.
</description>
<tutorials>
</tutorials>
<methods>
<method name="_get_component_type" qualifiers="virtual const">
<return type="int" />
<description>
Return the component type for the component we store data for.
</description>
</method>
<method name="_get_structure_data" qualifiers="virtual const">
<return type="int" />
<param index="0" name="next" type="int" />
<description>
Return a pointer to the structure data that will be submitted along with the snapshot query. This pointer must remain valid as long as this object is instantiated.
</description>
</method>
<method name="_set_capacity" qualifiers="virtual">
<return type="void" />
<param index="0" name="capacity" type="int" />
<description>
Set the expected capacity as provided by the spatial entities query system. Buffers should be initialized with the correct storage.
</description>
</method>
<method name="set_capacity">
<return type="void" />
<param index="0" name="capacity" type="int" />
<description>
Set the expected capacity as provided by the spatial entities query system. Buffers should be initialized with the correct storage.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentMarkerList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries marker result data.
</brief_description>
<description>
Object for storing the queries marker result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_marker_data" qualifiers="const">
<return type="Variant" />
<param index="0" name="snapshot" type="RID" />
<param index="1" name="index" type="int" />
<description>
Returns either a [String] or a [PackedByteArray] buffer with data for the marker at this [param index]. Only applicable for QR code markers.
</description>
</method>
<method name="get_marker_id" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the marker ID for the marker at this [param index]. Only applicable for Aruco or April Tag markers.
</description>
</method>
<method name="get_marker_type" qualifiers="const">
<return type="int" enum="OpenXRSpatialComponentMarkerList.MarkerType" />
<param index="0" name="index" type="int" />
<description>
Returns the marker type for the marker at this [param index].
</description>
</method>
</methods>
<constants>
<constant name="MARKER_TYPE_UNKNOWN" value="0" enum="MarkerType">
Unknown or unset marker type.
</constant>
<constant name="MARKER_TYPE_QRCODE" value="1" enum="MarkerType">
Marker based on a QR code.
</constant>
<constant name="MARKER_TYPE_MICRO_QRCODE" value="2" enum="MarkerType">
Marker based on a micro QR code.
</constant>
<constant name="MARKER_TYPE_ARUCO" value="3" enum="MarkerType">
Marker based on an Aruco code.
</constant>
<constant name="MARKER_TYPE_APRIL_TAG" value="4" enum="MarkerType">
Marker based on an April Tag.
</constant>
<constant name="MARKER_TYPE_MAX" value="5" enum="MarkerType">
Maximum value for this enum.
</constant>
</constants>
</class>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentMesh2DList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries mesh2d result data.
</brief_description>
<description>
Object for storing the queries 2D mesh result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_indices" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="snapshot" type="RID" />
<param index="1" name="index" type="int" />
<description>
Returns the mesh indices for the entity at this [param index].
</description>
</method>
<method name="get_transform" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="index" type="int" />
<description>
Returns the transform for positioning our mesh for the entity at this [param index].
</description>
</method>
<method name="get_vertices" qualifiers="const">
<return type="PackedVector2Array" />
<param index="0" name="snapshot" type="RID" />
<param index="1" name="index" type="int" />
<description>
Returns the mesh vertices for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentMesh3DList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries mesh3d result data.
</brief_description>
<description>
Object for storing the queries 3d mesh result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_mesh" qualifiers="const">
<return type="Mesh" />
<param index="0" name="index" type="int" />
<description>
Returns the mesh for the entity at this [param index].
</description>
</method>
<method name="get_transform" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="index" type="int" />
<description>
Returns the transform for positioning our mesh for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentParentList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries parent result data.
</brief_description>
<description>
Object for storing the queries parent result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_parent" qualifiers="const">
<return type="RID" />
<param index="0" name="index" type="int" />
<description>
Returns the RID for the parent entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentPersistenceList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the query persistence result data.
</brief_description>
<description>
Object for storing the query persistence result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_persistent_state" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the persistent state ([code]XrSpatialPersistenceStateEXT[/code]) for the entity at this [param index].
</description>
</method>
<method name="get_persistent_uuid" qualifiers="const">
<return type="String" />
<param index="0" name="index" type="int" />
<description>
Returns the persistent uuid for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentPlaneAlignmentList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries plane alignment result data.
</brief_description>
<description>
Object for storing the queries plane alignment result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_plane_alignment" qualifiers="const">
<return type="int" enum="OpenXRSpatialComponentPlaneAlignmentList.PlaneAlignment" />
<param index="0" name="index" type="int" />
<description>
Returns the plane alignment for the parent entity at this [param index].
</description>
</method>
</methods>
<constants>
<constant name="PLANE_ALIGNMENT_HORIZONTAL_UPWARD" value="0" enum="PlaneAlignment">
Plane is facing upward.
</constant>
<constant name="PLANE_ALIGNMENT_HORIZONTAL_DOWNWARD" value="1" enum="PlaneAlignment">
Plane is facing downwards.
</constant>
<constant name="PLANE_ALIGNMENT_VERTICAL" value="2" enum="PlaneAlignment">
Plane is vertically aligned.
</constant>
<constant name="PLANE_ALIGNMENT_ARBITRARY" value="3" enum="PlaneAlignment">
Plane has an arbitrary alignment.
</constant>
</constants>
</class>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentPlaneSemanticLabelList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries plane semantic label result data.
</brief_description>
<description>
Object for storing the queries plane semantic label result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_plane_semantic_label" qualifiers="const">
<return type="int" enum="OpenXRSpatialComponentPlaneSemanticLabelList.PlaneSemanticLabel" />
<param index="0" name="index" type="int" />
<description>
Returns the plane semantic label for the parent entity at this [param index].
</description>
</method>
</methods>
<constants>
<constant name="PLANE_SEMANTIC_LABEL_UNCATEGORIZED" value="1" enum="PlaneSemanticLabel">
Uncategorized plane.
</constant>
<constant name="PLANE_SEMANTIC_LABEL_FLOOR" value="2" enum="PlaneSemanticLabel">
Plane represents a floor.
</constant>
<constant name="PLANE_SEMANTIC_LABEL_WALL" value="3" enum="PlaneSemanticLabel">
Plane represents a wall.
</constant>
<constant name="PLANE_SEMANTIC_LABEL_CEILING" value="4" enum="PlaneSemanticLabel">
Plane represents a ceiling.
</constant>
<constant name="PLANE_SEMANTIC_LABEL_TABLE" value="5" enum="PlaneSemanticLabel">
Plane represents the surface of a table.
</constant>
</constants>
</class>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialComponentPolygon2DList" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the queries polygon2d result data.
</brief_description>
<description>
Object for storing the queries 2D polygon result data when calling [method OpenXRSpatialEntityExtension.query_snapshot].
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_transform" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="index" type="int" />
<description>
Returns the transform for positioning our polygon for the entity at this [param index].
</description>
</method>
<method name="get_vertices" qualifiers="const">
<return type="PackedVector2Array" />
<param index="0" name="snapshot" type="RID" />
<param index="1" name="index" type="int" />
<description>
Returns the polygon vertices for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialContextPersistenceConfig" inherits="OpenXRStructureBase" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration header for spatial persistence.
</brief_description>
<description>
Configuration header for spatial persistence. Pass this to [method OpenXRSpatialEntityExtension.create_spatial_context] as the next parameter to create a spatial context with spatial persistence capabilities.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_persistence_context">
<return type="void" />
<param index="0" name="persistence_context" type="RID" />
<description>
Adds a persistence context to this configuration. You must add at least one persistence context to create a valid configuration. You can create a persistence context by calling [method OpenXRSpatialAnchorCapability.create_persistence_context].
</description>
</method>
<method name="remove_persistence_context">
<return type="void" />
<param index="0" name="persistence_context" type="RID" />
<description>
Removes a persistence context.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,277 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialEntityExtension" inherits="OpenXRExtensionWrapper" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
OpenXR extension that handles spatial entities.
</brief_description>
<description>
OpenXR extension that handles spatial entities and, when enabled, allows querying those spatial entities. This extension will also automatically manage [XRTracker] objects for static entities.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_spatial_entity">
<return type="RID" />
<param index="0" name="spatial_context" type="RID" />
<param index="1" name="entity_id" type="int" />
<param index="2" name="entity" type="int" />
<description>
Registers an entity that was created directly on the OpenXR runtime.
</description>
</method>
<method name="create_spatial_context">
<return type="OpenXRFutureResult" />
<param index="0" name="capability_configurations" type="OpenXRSpatialCapabilityConfigurationBaseHeader[]" />
<param index="1" name="next" type="OpenXRStructureBase" default="null" />
<param index="2" name="user_callback" type="Callable" default="Callable()" />
<description>
Creates a new spatial context that handles entities for the provided capability configurations. [param capability_configurations] is an array of [OpenXRSpatialCapabilityConfigurationBaseHeader] with the needed capability configuration data.
[param next] is an optional parameter that can contain additional information for creating our spatial context.
[b]Note:[/b] This is an asynchronous method and returns an [OpenXRFutureResult] object with which to track the status, discarding this object will not cancel the creation process. On success [param user_callback] will be called if specified. The result data for this function is the [RID] for our spatial context.
</description>
</method>
<method name="discover_spatial_entities">
<return type="OpenXRFutureResult" />
<param index="0" name="spatial_context" type="RID" />
<param index="1" name="component_types" type="PackedInt64Array" />
<param index="2" name="next" type="OpenXRStructureBase" default="null" />
<param index="3" name="user_callback" type="Callable" default="Callable()" />
<description>
Starts a new discovery query, this will gather all objects tracked by the [param spatial_context] that have at least one of the component types specified in [param component_types].
[param next] is an optional parameter that can contain additional information for executing the discovery query.
[b]Note:[/b] This is an asynchronous method and returns an [OpenXRFutureResult] object with which to track the status, discarding this object will not cancel the discovery process. On success [param user_callback] will be called if specified. The result data for this function is the [RID] for our snapshot.
</description>
</method>
<method name="find_spatial_entity">
<return type="RID" />
<param index="0" name="entity_id" type="int" />
<description>
Returns the [RID] for the specified spatial entity ID.
</description>
</method>
<method name="free_spatial_context">
<return type="void" />
<param index="0" name="spatial_context" type="RID" />
<description>
Frees a spatial context previously created when calling [method create_spatial_context]. If the spatial context creation is still ongoing, the asynchronous process is cancelled.
</description>
</method>
<method name="free_spatial_entity">
<return type="void" />
<param index="0" name="entity" type="RID" />
<description>
Frees an entity previously created when calling [method add_spatial_entity] or [method make_spatial_entity].
</description>
</method>
<method name="free_spatial_snapshot">
<return type="void" />
<param index="0" name="spatial_snapshot" type="RID" />
<description>
Frees a spatial snapshot previously created when calling [method discover_spatial_entities]. If the spatial snapshot creation is still ongoing, the asynchronous process is cancelled.
</description>
</method>
<method name="get_float_buffer" qualifiers="const">
<return type="PackedFloat32Array" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a buffer with floats from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="get_spatial_context_handle" qualifiers="const">
<return type="int" />
<param index="0" name="spatial_context" type="RID" />
<description>
Returns the OpenXR spatial context handle for this snapshot.
[b]Note:[/b] This method is intended to be used from GDExtensions that implement spatial entity capability handlers.
</description>
</method>
<method name="get_spatial_context_ready" qualifiers="const">
<return type="bool" />
<param index="0" name="spatial_context" type="RID" />
<description>
Returns [code]true[/code] if the spatial context finished its creation and is ready to be used.
</description>
</method>
<method name="get_spatial_entity_context" qualifiers="const">
<return type="RID" />
<param index="0" name="entity" type="RID" />
<description>
Returns the spatial context for this entity.
</description>
</method>
<method name="get_spatial_entity_id" qualifiers="const">
<return type="int" />
<param index="0" name="entity" type="RID" />
<description>
Returns the internal [code]XrSpatialEntityIdEXT[/code] associated with the entity.
</description>
</method>
<method name="get_spatial_snapshot_context" qualifiers="const">
<return type="RID" />
<param index="0" name="spatial_snapshot" type="RID" />
<description>
Returns the spatial context related to this spatial snapshot.
</description>
</method>
<method name="get_spatial_snapshot_handle" qualifiers="const">
<return type="int" />
<param index="0" name="spatial_snapshot" type="RID" />
<description>
Returns the OpenXR spatial snapshot handle for this snapshot.
[b]Note:[/b] This method is intended to be used from GDExtensions that implement spatial entity capability handlers.
</description>
</method>
<method name="get_string" qualifiers="const">
<return type="String" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a string from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="get_uint8_buffer" qualifiers="const">
<return type="PackedByteArray" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a buffer with 8 bit ints from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="get_uint16_buffer" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a buffer with 16 bit ints from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="get_uint32_buffer" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a buffer with 32 bit ints from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="get_vector2_buffer" qualifiers="const">
<return type="PackedVector2Array" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a buffer with [Vector2] entries from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="get_vector3_buffer" qualifiers="const">
<return type="PackedVector3Array" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="buffer_id" type="int" />
<description>
Returns a buffer with [Vector3] entries from a buffer that was retrieved when taking a snapshot.
</description>
</method>
<method name="make_spatial_entity">
<return type="RID" />
<param index="0" name="spatial_context" type="RID" />
<param index="1" name="entity_id" type="int" />
<description>
Creates a new entity for this [param entity_id]. The [param spatial_context] should match the context that discovered the entity.
</description>
</method>
<method name="query_snapshot">
<return type="bool" />
<param index="0" name="spatial_snapshot" type="RID" />
<param index="1" name="component_data" type="OpenXRSpatialComponentData[]" />
<param index="2" name="next" type="OpenXRStructureBase" default="null" />
<description>
Queries the snapshot data. This will find all entities in the snapshot that contain all requested components in [param component_data]. The objects held within [param component_data] will then be populated with the queried data. [param component_data] must always have an object of [OpenXRSpatialQueryResultData] as the first entry.
[param next] is an optional parameter that can contain additional information passed when setting our query conditions.
</description>
</method>
<method name="supports_capability">
<return type="bool" />
<param index="0" name="capability" type="int" enum="OpenXRSpatialEntityExtension.Capability" />
<description>
Returns [code]true[/code] if this spatial entity [param capability] is supported by the hardware used.
</description>
</method>
<method name="supports_component_type">
<return type="bool" />
<param index="0" name="capability" type="int" enum="OpenXRSpatialEntityExtension.Capability" />
<param index="1" name="component_type" type="int" enum="OpenXRSpatialEntityExtension.ComponentType" />
<description>
Returns [code]true[/code] if this [param capability] supports the [param component_type].
</description>
</method>
<method name="update_spatial_entities">
<return type="RID" />
<param index="0" name="spatial_context" type="RID" />
<param index="1" name="entities" type="RID[]" />
<param index="2" name="component_types" type="PackedInt64Array" />
<param index="3" name="next" type="OpenXRStructureBase" default="null" />
<description>
Performs a snapshot for a limited number of entities. This is NOT an asynchronous method and will return the snapshot immediately.
</description>
</method>
</methods>
<signals>
<signal name="spatial_discovery_recommended">
<param index="0" name="spatial_context" type="RID" />
<description>
Emitted when OpenXR recommends running a discovery query because entities managed by this spatial context have (likely) changed.
</description>
</signal>
</signals>
<constants>
<constant name="CAPABILITY_PLANE_TRACKING" value="1000741000" enum="Capability">
Plane tracking capability.
</constant>
<constant name="CAPABILITY_MARKER_TRACKING_QR_CODE" value="1000743000" enum="Capability">
QR code based marker tracking capability.
</constant>
<constant name="CAPABILITY_MARKER_TRACKING_MICRO_QR_CODE" value="1000743001" enum="Capability">
Micro QR code based marker tracking capability.
</constant>
<constant name="CAPABILITY_MARKER_TRACKING_ARUCO_MARKER" value="1000743002" enum="Capability">
Aruco marker based marker tracking capability.
</constant>
<constant name="CAPABILITY_MARKER_TRACKING_APRIL_TAG" value="1000743003" enum="Capability">
April tag based marker tracking capability.
</constant>
<constant name="CAPABILITY_ANCHOR" value="1000762000" enum="Capability">
Anchor capability.
</constant>
<constant name="COMPONENT_TYPE_BOUNDED_2D" value="1" enum="ComponentType">
Component that provides the 2D bounds for a spatial entity. The corresponding list structure is [code]XrSpatialComponentBounded2DListEXT[/code]; the corresponding data structure is [code]XrSpatialBounded2DDataEXT[/code].
</constant>
<constant name="COMPONENT_TYPE_BOUNDED_3D" value="2" enum="ComponentType">
Component that provides the 3D bounds for a spatial entity. The corresponding list structure is [code]XrSpatialComponentBounded3DListEXT[/code]; the corresponding data structure is [code]XrBoxf[/code].
</constant>
<constant name="COMPONENT_TYPE_PARENT" value="3" enum="ComponentType">
Component that provides the XrSpatialEntityIdEXT of the parent for a spatial entity. The corresponding list structure is [code]XrSpatialComponentParentListEXT[/code]; the corresponding data structure is [code]XrSpatialEntityIdEXT[/code].
</constant>
<constant name="COMPONENT_TYPE_MESH_3D" value="4" enum="ComponentType">
Component that provides a 3D mesh for a spatial entity. The corresponding list structure is [code]XrSpatialComponentMesh3DListEXT[/code]; the corresponding data structure is [code]XrSpatialMeshDataEXT[/code].
</constant>
<constant name="COMPONENT_TYPE_PLANE_ALIGNMENT" value="1000741000" enum="ComponentType">
Component that provides the plane alignment enum for a spatial entity. The corresponding list structure is [code]XrSpatialComponentPlaneAlignmentListEXT[/code]; the corresponding data structure is [code]XrSpatialPlaneAlignmentEXT[/code] (Added by the [code]XR_EXT_spatial_plane_tracking[/code] extension).
</constant>
<constant name="COMPONENT_TYPE_MESH_2D" value="1000741001" enum="ComponentType">
Component that provides a 2D mesh for a spatial entity. The corresponding list structure is [code]XrSpatialComponentMesh2DListEXT[/code]; the corresponding data structure is [code]XrSpatialMeshDataEXT[/code] (Added by the [code]XR_EXT_spatial_plane_tracking[/code] extension).
</constant>
<constant name="COMPONENT_TYPE_POLYGON_2D" value="1000741002" enum="ComponentType">
Component that provides a 2D boundary polygon for a spatial entity. The corresponding list structure is [code]XrSpatialComponentPolygon2DListEXT[/code]; the corresponding data structure is [code]XrSpatialPolygon2DDataEXT[/code] (Added by the [code]XR_EXT_spatial_plane_tracking[/code] extension).
</constant>
<constant name="COMPONENT_TYPE_PLANE_SEMANTIC_LABEL" value="1000741003" enum="ComponentType">
Component that provides a semantic label for a plane. The corresponding list structure is [code]XrSpatialComponentPlaneSemanticLabelListEXT[/code]; the corresponding data structure is [code]XrSpatialPlaneSemanticLabelEXT[/code] (Added by the [code]XR_EXT_spatial_plane_tracking[/code] extension).
</constant>
<constant name="COMPONENT_TYPE_MARKER" value="1000743000" enum="ComponentType">
A component describing the marker type, ID and location. The corresponding list structure is [code]XrSpatialComponentMarkerListEXT[/code]; the corresponding data structure is [code]XrSpatialMarkerDataEXT[/code] (Added by the [code]XR_EXT_spatial_marker_tracking[/code] extension).
</constant>
<constant name="COMPONENT_TYPE_ANCHOR" value="1000762000" enum="ComponentType">
Component that provides the location for an anchor. The corresponding list structure is [code]XrSpatialComponentAnchorListEXT[/code]; the corresponding data structure is [code]XrPosef[/code] (Added by the [code]XR_EXT_spatial_anchor[/code] extension).
</constant>
<constant name="COMPONENT_TYPE_PERSISTENCE" value="1000763000" enum="ComponentType">
Component that provides the persisted UUID for a spatial entity. The corresponding list structure is [code]XrSpatialComponentPersistenceListEXT; the corresponding data structure is [code]XrSpatialPersistenceDataEXT[/code] (Added by the [code]XR_EXT_spatial_persistence[/code] extension).
</constant>
</constants>
</class>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialEntityTracker" inherits="XRPositionalTracker" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Base class for Positional trackers managed by OpenXR's spatial entity extensions.
</brief_description>
<description>
These are trackers created and managed by OpenXR's spatial entity extensions that give access to specific data related to OpenXR's spatial entities. They will always be of type [code]TRACKER_ANCHOR[/code].
</description>
<tutorials>
</tutorials>
<members>
<member name="entity" type="RID" setter="set_entity" getter="get_entity" default="RID()">
The spatial entity associated with this tracker.
</member>
<member name="spatial_tracking_state" type="int" setter="set_spatial_tracking_state" getter="get_spatial_tracking_state" enum="OpenXRSpatialEntityTracker.EntityTrackingState" default="2">
The spatial tracking state for this tracker.
</member>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" overrides="XRTracker" enum="XRServer.TrackerType" default="8" />
</members>
<signals>
<signal name="spatial_tracking_state_changed">
<param index="0" name="spatial_tracking_state" type="int" />
<description>
</description>
</signal>
</signals>
<constants>
<constant name="ENTITY_TRACKING_STATE_STOPPED" value="1" enum="EntityTrackingState">
This anchor has stopped tracking.
</constant>
<constant name="ENTITY_TRACKING_STATE_PAUSED" value="2" enum="EntityTrackingState">
Tracking is currently paused.
</constant>
<constant name="ENTITY_TRACKING_STATE_TRACKING" value="3" enum="EntityTrackingState">
This anchor is currently being tracked.
</constant>
</constants>
</class>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialMarkerTrackingCapability" inherits="OpenXRExtensionWrapper" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Implementation for handling spatial entity marker tracking logic.
</brief_description>
<description>
This class handles the OpenXR marker tracking spatial entity extension.
</description>
<tutorials>
</tutorials>
<methods>
<method name="is_april_tag_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if April tag marker tracking is supported by the current device.
</description>
</method>
<method name="is_aruco_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if Aruco marker tracking is supported by the current device.
</description>
</method>
<method name="is_micro_qrcode_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if micro QR code marker tracking is supported by the current device.
</description>
</method>
<method name="is_qrcode_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if QR code marker tracking is supported by the current device.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialPlaneTrackingCapability" inherits="OpenXRExtensionWrapper" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Implementation for handling spatial entity plane tracking logic.
</brief_description>
<description>
This class handles the OpenXR plane tracking spatial entity extension.
</description>
<tutorials>
</tutorials>
<methods>
<method name="is_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if plane tracking is supported by the current device.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRSpatialQueryResultData" inherits="OpenXRSpatialComponentData" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing the main query result data.
</brief_description>
<description>
Object for storing the main query result data when calling [method OpenXRSpatialEntityExtension.query_snapshot]. This must always be the first component requested.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_capacity" qualifiers="const">
<return type="int" />
<description>
Returns the number of entities that were retrieved.
</description>
</method>
<method name="get_entity_id" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the entity id ([code]XrSpatialEntityIdEXT[/code]) for the entity at this [param index].
</description>
</method>
<method name="get_entity_state" qualifiers="const">
<return type="int" enum="OpenXRSpatialEntityTracker.EntityTrackingState" />
<param index="0" name="index" type="int" />
<description>
Returns the entity state for the entity at this [param index].
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OpenXRStructureBase" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Object for storing OpenXR structure data.
</brief_description>
<description>
Object for storing OpenXR structure data that is passed when calling into OpenXR APIs.
</description>
<tutorials>
</tutorials>
<methods>
<method name="_get_header" qualifiers="virtual">
<return type="int" />
<param index="0" name="next" type="int" />
<description>
</description>
</method>
<method name="get_structure_type">
<return type="int" />
<description>
Returns the structure type (OpenXR [code]XrStructureType[/code]) used for this structure.
</description>
</method>
</methods>
<members>
<member name="next" type="OpenXRStructureBase" setter="set_next" getter="get_next">
Setting another structure object here chains these structures together to extend the API functionality. Consult the OpenXR documentation for which structures can be used with a given API call.
</member>
</members>
</class>

View file

@ -7,6 +7,7 @@ Import("env_openxr")
module_obj = [] module_obj = []
env_openxr.add_source_files(module_obj, "*.cpp") env_openxr.add_source_files(module_obj, "*.cpp")
env_openxr.add_source_files(module_obj, "spatial_entities/*.cpp")
# These are platform dependent # These are platform dependent
if env["platform"] == "android": if env["platform"] == "android":

View file

@ -73,7 +73,7 @@ public:
// You should return the pointer to the last struct you define as your result. // You should return the pointer to the last struct you define as your result.
// If you are not adding any structs, just return `p_next_pointer`. // If you are not adding any structs, just return `p_next_pointer`.
// See existing extensions for examples of this implementation. // See existing extensions for examples of this implementation.
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when we interrogate OpenXRS system abilities. virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when we interrogate OpenXR's system abilities.
virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when we create our OpenXR instance. virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when we create our OpenXR instance.
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when we create our OpenXR session. virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when we create our OpenXR session.
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when creating OpenXR swap chains. virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when creating OpenXR swap chains.

View file

@ -31,7 +31,7 @@
#pragma once #pragma once
/* /*
The OpenXR future extension forms the basis of OpenXRs ability to The OpenXR future extension forms the basis of OpenXR's ability to
execute logic asynchronously. execute logic asynchronously.
Asynchronous functions will return a future object which can be Asynchronous functions will return a future object which can be

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,256 @@
/**************************************************************************/
/* openxr_spatial_anchor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../../openxr_util.h"
#include "openxr_spatial_entities.h"
#include "openxr_spatial_entity_extension.h"
// Anchor capability configuration
class OpenXRSpatialCapabilityConfigurationAnchor : public OpenXRSpatialCapabilityConfigurationBaseHeader {
GDCLASS(OpenXRSpatialCapabilityConfigurationAnchor, OpenXRSpatialCapabilityConfigurationBaseHeader);
public:
virtual bool has_valid_configuration() const override;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration() override;
Vector<XrSpatialComponentTypeEXT> get_enabled_components() const { return anchor_enabled_components; }
protected:
static void _bind_methods();
private:
Vector<XrSpatialComponentTypeEXT> anchor_enabled_components;
XrSpatialCapabilityConfigurationAnchorEXT anchor_config = { XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT, nullptr, XR_SPATIAL_CAPABILITY_ANCHOR_EXT, 0, nullptr };
PackedInt64Array _get_enabled_components() const;
};
// Anchor component anchor list
class OpenXRSpatialComponentAnchorList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentAnchorList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
Transform3D get_entity_pose(int64_t p_index) const;
private:
Vector<XrPosef> entity_poses;
XrSpatialComponentAnchorListEXT anchor_list = { XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT, nullptr, 0, nullptr };
};
// Persistence configuration
class OpenXRSpatialContextPersistenceConfig : public OpenXRStructureBase {
GDCLASS(OpenXRSpatialContextPersistenceConfig, OpenXRStructureBase);
public:
bool has_valid_configuration() const;
virtual void *get_header(void *p_next) override;
virtual XrStructureType get_structure_type() override;
void add_persistence_context(RID p_persistence_context);
void remove_persistence_context(RID p_persistence_context);
protected:
static void _bind_methods();
private:
Vector<RID> persistence_contexts;
Vector<XrSpatialPersistenceContextEXT> context_handles;
XrSpatialContextPersistenceConfigEXT persistence_config = { XR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXT, nullptr, 0, nullptr };
};
// Component persistence list
class OpenXRSpatialComponentPersistenceList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentPersistenceList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
XrUuid get_persistent_uuid(int64_t p_index) const;
XrSpatialPersistenceStateEXT get_persistent_state(int64_t p_index) const;
static String get_persistence_state_name(XrSpatialPersistenceStateEXT p_state);
private:
Vector<XrSpatialPersistenceDataEXT> persist_data;
XrSpatialComponentPersistenceListEXT persistence_list = { XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT, nullptr, 0, nullptr };
String _get_persistent_uuid(int64_t p_index) const;
uint64_t _get_persistent_state(int64_t p_index) const;
};
// Anchor tracker, this adds no new logic, it's purely for typing!
class OpenXRAnchorTracker : public OpenXRSpatialEntityTracker {
GDCLASS(OpenXRAnchorTracker, OpenXRSpatialEntityTracker);
protected:
static void _bind_methods();
public:
bool has_uuid() const;
XrUuid get_uuid() const;
void set_uuid(const XrUuid &p_uuid);
private:
XrUuid uuid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
String _get_uuid() const;
void _set_uuid(const String &p_uuid);
bool uuid_is_equal(const XrUuid &p_a, const XrUuid &p_b);
};
// (Persistent) anchor logic
class OpenXRSpatialAnchorCapability : public OpenXRExtensionWrapper {
GDCLASS(OpenXRSpatialAnchorCapability, OpenXRExtensionWrapper);
public:
enum PersistenceScope {
PERSISTENCE_SCOPE_SYSTEM_MANAGED = XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT,
PERSISTENCE_SCOPE_LOCAL_ANCHORS = XR_SPATIAL_PERSISTENCE_SCOPE_LOCAL_ANCHORS_EXT,
};
static OpenXRSpatialAnchorCapability *get_singleton();
OpenXRSpatialAnchorCapability();
virtual ~OpenXRSpatialAnchorCapability() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_instance_destroyed() override;
virtual void on_session_created(const XrSession p_session) override;
virtual void on_session_destroyed() override;
virtual void on_process() override;
bool is_spatial_anchor_supported();
bool is_spatial_persistence_supported();
// Persistence scopes
bool is_persistence_scope_supported(XrSpatialPersistenceScopeEXT p_scope);
Ref<OpenXRFutureResult> create_persistence_context(XrSpatialPersistenceScopeEXT p_scope, const Callable &p_user_callback = Callable());
XrSpatialPersistenceContextEXT get_persistence_context_handle(RID p_persistence_context) const;
void free_persistence_context(RID p_persistence_context);
Ref<OpenXRAnchorTracker> create_new_anchor(const Transform3D &p_transform, RID p_spatial_context = RID());
void remove_anchor(Ref<OpenXRAnchorTracker> p_anchor_tracker);
Ref<OpenXRFutureResult> persist_anchor(Ref<OpenXRAnchorTracker> p_anchor_tracker, RID p_persistence_context = RID(), const Callable &p_user_callback = Callable());
Ref<OpenXRFutureResult> unpersist_anchor(Ref<OpenXRAnchorTracker> p_anchor_tracker, RID p_persistence_context = RID(), const Callable &p_user_callback = Callable());
static String get_spatial_persistence_scope_name(XrSpatialPersistenceScopeEXT p_scope);
static String get_spatial_persistence_context_result_name(XrSpatialPersistenceContextResultEXT p_result);
protected:
static void _bind_methods();
private:
static OpenXRSpatialAnchorCapability *singleton;
bool spatial_anchor_ext = false;
bool spatial_persistence_ext = false;
bool spatial_persistence_operations_ext = false;
bool spatial_anchor_supported = false;
RID spatial_context;
RID persistence_context;
bool need_discovery = false;
int discovery_cooldown = 0;
Ref<OpenXRFutureResult> discovery_query_result;
Ref<OpenXRSpatialCapabilityConfigurationAnchor> anchor_configuration;
Ref<OpenXRSpatialContextPersistenceConfig> persistence_configuration;
Vector<XrSpatialPersistenceScopeEXT> supported_persistence_scopes;
bool _load_supported_persistence_scopes();
// Persistence scopes
struct PersistenceContextData {
XrSpatialPersistenceScopeEXT scope;
XrSpatialPersistenceContextEXT persistence_context = XR_NULL_HANDLE;
};
mutable RID_Owner<PersistenceContextData> persistence_context_owner;
bool _is_persistence_scope_supported(PersistenceScope p_scope);
Ref<OpenXRFutureResult> _create_persistence_context(PersistenceScope p_scope, Callable p_user_callback = Callable());
uint64_t _get_persistence_context_handle(RID p_persistence_context) const;
void _on_persistence_context_ready(Ref<OpenXRFutureResult> p_future_result, uint64_t p_scope, Callable p_user_callback = Callable());
// Discovery logic
void _on_persistence_context_completed(RID p_persistence_context);
Ref<OpenXRFutureResult> _create_spatial_context();
void _on_spatial_context_created(RID p_spatial_context);
void _on_spatial_discovery_recommended(RID p_spatial_context);
Ref<OpenXRFutureResult> _start_entity_discovery();
void _process_discovery_snapshot(RID p_snapshot);
void _process_update_snapshot(RID p_snapshot);
// Entities
void _on_made_anchor_persistent(Ref<OpenXRFutureResult> p_future_result, RID p_persistence_context, Ref<OpenXRAnchorTracker> p_anchor_tracker, const Callable &p_callback);
void _on_made_anchor_unpersistent(Ref<OpenXRFutureResult> p_future_result, RID p_persistence_context, Ref<OpenXRAnchorTracker> p_anchor_tracker, const Callable &p_callback);
// Trackers
HashMap<XrSpatialEntityIdEXT, Ref<OpenXRAnchorTracker>> anchors;
// OpenXR API call wrappers
EXT_PROTO_XRRESULT_FUNC4(xrCreateSpatialAnchorEXT, (XrSpatialContextEXT), spatialContext, (const XrSpatialAnchorCreateInfoEXT *), create_info, (XrSpatialEntityIdEXT *), anchor_entity_id, (XrSpatialEntityEXT *), anchor_entity);
EXT_PROTO_XRRESULT_FUNC5(xrEnumerateSpatialPersistenceScopesEXT, (XrInstance), instance, (XrSystemId), system_id, (uint32_t), persistence_scope_capacity_input, (uint32_t *), persistence_scope_count_output, (XrSpatialPersistenceScopeEXT *), persistence_scopes);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialPersistenceContextAsyncEXT, (XrSession), session, (const XrSpatialPersistenceContextCreateInfoEXT *), create_info, (XrFutureEXT *), future);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialPersistenceContextCompleteEXT, (XrSession), session, (XrFutureEXT), future, (XrCreateSpatialPersistenceContextCompletionEXT *), completion);
EXT_PROTO_XRRESULT_FUNC1(xrDestroySpatialPersistenceContextEXT, (XrSpatialPersistenceContextEXT), persistence_context);
EXT_PROTO_XRRESULT_FUNC3(xrPersistSpatialEntityAsyncEXT, (XrSpatialPersistenceContextEXT), persistence_context, (const XrSpatialEntityPersistInfoEXT *), persist_info, (XrFutureEXT *), future);
EXT_PROTO_XRRESULT_FUNC3(xrPersistSpatialEntityCompleteEXT, (XrSpatialPersistenceContextEXT), persistence_context, (XrFutureEXT), future, (XrPersistSpatialEntityCompletionEXT *), completion);
EXT_PROTO_XRRESULT_FUNC3(xrUnpersistSpatialEntityAsyncEXT, (XrSpatialPersistenceContextEXT), persistence_context, (const XrSpatialEntityUnpersistInfoEXT *), unpersist_info, (XrFutureEXT *), future);
EXT_PROTO_XRRESULT_FUNC3(xrUnpersistSpatialEntityCompleteEXT, (XrSpatialPersistenceContextEXT), persistence_context, (XrFutureEXT), future, (XrUnpersistSpatialEntityCompletionEXT *), completion);
};
VARIANT_ENUM_CAST(OpenXRSpatialAnchorCapability::PersistenceScope);

View file

@ -0,0 +1,504 @@
/**************************************************************************/
/* openxr_spatial_entities.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "openxr_spatial_entities.h"
#include "../../openxr_api.h"
#include "core/variant/native_ptr.h"
#include "openxr_spatial_entity_extension.h"
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialCapabilityConfigurationBaseHeader
void OpenXRSpatialCapabilityConfigurationBaseHeader::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_valid_configuration"), &OpenXRSpatialCapabilityConfigurationBaseHeader::has_valid_configuration);
GDVIRTUAL_BIND(_has_valid_configuration);
GDVIRTUAL_BIND(_get_configuration);
}
bool OpenXRSpatialCapabilityConfigurationBaseHeader::has_valid_configuration() const {
bool is_valid = false;
if (GDVIRTUAL_CALL(_has_valid_configuration, is_valid)) {
return is_valid;
}
return false;
}
XrSpatialCapabilityConfigurationBaseHeaderEXT *OpenXRSpatialCapabilityConfigurationBaseHeader::get_configuration() {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_get_configuration, pointer)) {
return reinterpret_cast<XrSpatialCapabilityConfigurationBaseHeaderEXT *>(pointer);
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialEntityTracker
void OpenXRSpatialEntityTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_entity", "entity"), &OpenXRSpatialEntityTracker::set_entity);
ClassDB::bind_method(D_METHOD("get_entity"), &OpenXRSpatialEntityTracker::get_entity);
ADD_PROPERTY(PropertyInfo(Variant::RID, "entity"), "set_entity", "get_entity");
ClassDB::bind_method(D_METHOD("set_spatial_tracking_state", "spatial_tracking_state"), &OpenXRSpatialEntityTracker::_set_spatial_tracking_state);
ClassDB::bind_method(D_METHOD("get_spatial_tracking_state"), &OpenXRSpatialEntityTracker::_get_spatial_tracking_state);
ADD_PROPERTY(PropertyInfo(Variant::INT, "spatial_tracking_state"), "set_spatial_tracking_state", "get_spatial_tracking_state");
ADD_SIGNAL(MethodInfo("spatial_tracking_state_changed", PropertyInfo(Variant::INT, "spatial_tracking_state")));
BIND_ENUM_CONSTANT(ENTITY_TRACKING_STATE_STOPPED);
BIND_ENUM_CONSTANT(ENTITY_TRACKING_STATE_PAUSED);
BIND_ENUM_CONSTANT(ENTITY_TRACKING_STATE_TRACKING);
}
OpenXRSpatialEntityTracker::OpenXRSpatialEntityTracker() {
set_tracker_type(XRServer::TrackerType::TRACKER_ANCHOR);
}
OpenXRSpatialEntityTracker::~OpenXRSpatialEntityTracker() {
if (spatial_entity.is_valid()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
if (se_extension) {
se_extension->free_spatial_entity(spatial_entity);
spatial_entity = RID();
}
}
}
void OpenXRSpatialEntityTracker::set_entity(const RID &p_entity) {
if (spatial_entity.is_valid()) {
if (spatial_entity == p_entity) {
return;
}
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
if (se_extension) {
se_extension->free_spatial_entity(spatial_entity);
spatial_entity = RID();
}
}
spatial_entity = p_entity;
if (p_entity.is_valid()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
XrSpatialEntityIdEXT entity_id = se_extension->get_spatial_entity_id(p_entity);
String tracker_name = String("openxr/spatial_entity/") + String::num_int64(entity_id);
set_tracker_name(tracker_name);
} else {
set_tracker_name("openxr/spatial_entity/null");
}
}
RID OpenXRSpatialEntityTracker::get_entity() const {
return spatial_entity;
}
void OpenXRSpatialEntityTracker::set_spatial_tracking_state(const XrSpatialEntityTrackingStateEXT p_state) {
if (spatial_tracking_state != p_state) {
spatial_tracking_state = p_state;
emit_signal(SNAME("spatial_tracking_state_changed"), spatial_tracking_state);
}
}
void OpenXRSpatialEntityTracker::_set_spatial_tracking_state(const EntityTrackingState p_state) {
set_spatial_tracking_state((XrSpatialEntityTrackingStateEXT)p_state);
}
XrSpatialEntityTrackingStateEXT OpenXRSpatialEntityTracker::get_spatial_tracking_state() const {
return spatial_tracking_state;
}
OpenXRSpatialEntityTracker::EntityTrackingState OpenXRSpatialEntityTracker::_get_spatial_tracking_state() const {
return (EntityTrackingState)get_spatial_tracking_state();
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialComponentData
void OpenXRSpatialComponentData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_capacity", "capacity"), &OpenXRSpatialComponentData::set_capacity);
GDVIRTUAL_BIND(_set_capacity, "capacity");
GDVIRTUAL_BIND(_get_component_type);
GDVIRTUAL_BIND(_get_structure_data, "next");
}
void OpenXRSpatialComponentData::set_capacity(uint32_t p_capacity) {
GDVIRTUAL_CALL(_set_capacity, p_capacity);
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentData::get_component_type() const {
uint64_t component_type = XR_SPATIAL_COMPONENT_TYPE_MAX_ENUM_EXT;
if (GDVIRTUAL_CALL(_get_component_type, component_type)) {
return (XrSpatialComponentTypeEXT)component_type;
}
return XR_SPATIAL_COMPONENT_TYPE_MAX_ENUM_EXT;
}
void *OpenXRSpatialComponentData::get_structure_data(void *p_next) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_get_structure_data, (uint64_t)p_next, pointer)) {
return reinterpret_cast<void *>(pointer);
}
return p_next;
}
////////////////////////////////////////////////////////////////////////////
// Spatial component bounded2d list
void OpenXRSpatialComponentBounded2DList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_center_pose", "index"), &OpenXRSpatialComponentBounded2DList::get_center_pose);
ClassDB::bind_method(D_METHOD("get_size", "index"), &OpenXRSpatialComponentBounded2DList::get_size);
}
void OpenXRSpatialComponentBounded2DList::set_capacity(uint32_t p_capacity) {
bounded2d_data.resize(p_capacity);
bounded2d_list.boundCount = uint32_t(bounded2d_data.size());
bounded2d_list.bounds = bounded2d_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentBounded2DList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT;
}
void *OpenXRSpatialComponentBounded2DList::get_structure_data(void *p_next) {
bounded2d_list.next = p_next;
return &bounded2d_list;
}
Transform3D OpenXRSpatialComponentBounded2DList::get_center_pose(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, bounded2d_data.size(), Transform3D());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Transform3D());
return openxr_api->transform_from_pose(bounded2d_data[p_index].center);
}
Vector2 OpenXRSpatialComponentBounded2DList::get_size(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, bounded2d_data.size(), Vector2());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Vector2());
const XrExtent2Df &extents = bounded2d_data[p_index].extents;
return Vector2(extents.width, extents.height);
}
////////////////////////////////////////////////////////////////////////////
// Spatial component bounded3d list
void OpenXRSpatialComponentBounded3DList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_center_pose", "index"), &OpenXRSpatialComponentBounded3DList::get_center_pose);
ClassDB::bind_method(D_METHOD("get_size", "index"), &OpenXRSpatialComponentBounded3DList::get_size);
}
void OpenXRSpatialComponentBounded3DList::set_capacity(uint32_t p_capacity) {
bounded3d_data.resize(p_capacity);
bounded3d_list.boundCount = uint32_t(bounded3d_data.size());
bounded3d_list.bounds = bounded3d_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentBounded3DList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_BOUNDED_3D_EXT;
}
void *OpenXRSpatialComponentBounded3DList::get_structure_data(void *p_next) {
bounded3d_list.next = p_next;
return &bounded3d_list;
}
Transform3D OpenXRSpatialComponentBounded3DList::get_center_pose(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, bounded3d_data.size(), Transform3D());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Transform3D());
return openxr_api->transform_from_pose(bounded3d_data[p_index].center);
}
Vector3 OpenXRSpatialComponentBounded3DList::get_size(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, bounded3d_data.size(), Vector3());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Vector3());
const XrExtent3Df &extents = bounded3d_data[p_index].extents;
return Vector3(extents.width, extents.height, extents.depth);
}
////////////////////////////////////////////////////////////////////////////
// Spatial component parent list
void OpenXRSpatialComponentParentList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_parent", "index"), &OpenXRSpatialComponentParentList::get_parent);
}
void OpenXRSpatialComponentParentList::set_capacity(uint32_t p_capacity) {
parent_data.resize(p_capacity);
parent_list.parentCount = uint32_t(parent_data.size());
parent_list.parents = parent_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentParentList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT;
}
void *OpenXRSpatialComponentParentList::get_structure_data(void *p_next) {
parent_list.next = p_next;
return &parent_list;
}
RID OpenXRSpatialComponentParentList::get_parent(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, parent_data.size(), RID());
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, RID());
return se_extension->find_spatial_entity(parent_data[p_index]);
}
////////////////////////////////////////////////////////////////////////////
// Spatial component mesh2d list
void OpenXRSpatialComponentMesh2DList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform", "index"), &OpenXRSpatialComponentMesh2DList::get_transform);
ClassDB::bind_method(D_METHOD("get_vertices", "snapshot", "index"), &OpenXRSpatialComponentMesh2DList::get_vertices);
ClassDB::bind_method(D_METHOD("get_indices", "snapshot", "index"), &OpenXRSpatialComponentMesh2DList::get_indices);
}
void OpenXRSpatialComponentMesh2DList::set_capacity(uint32_t p_capacity) {
mesh2d_data.resize(p_capacity);
mesh2d_list.meshCount = uint32_t(mesh2d_data.size());
mesh2d_list.meshes = mesh2d_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentMesh2DList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_MESH_2D_EXT;
}
void *OpenXRSpatialComponentMesh2DList::get_structure_data(void *p_next) {
mesh2d_list.next = p_next;
return &mesh2d_list;
}
Transform3D OpenXRSpatialComponentMesh2DList::get_transform(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, mesh2d_data.size(), Transform3D());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Transform3D());
return openxr_api->transform_from_pose(mesh2d_data[p_index].origin);
}
PackedVector2Array OpenXRSpatialComponentMesh2DList::get_vertices(RID p_snapshot, int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, mesh2d_data.size(), PackedVector2Array());
const XrSpatialBufferEXT &buffer = mesh2d_data[p_index].vertexBuffer;
if (buffer.bufferId == XR_NULL_SPATIAL_BUFFER_ID_EXT) {
// We don't have data (yet).
return PackedVector2Array();
}
ERR_FAIL_COND_V(buffer.bufferType != XR_SPATIAL_BUFFER_TYPE_VECTOR2F_EXT, PackedVector2Array());
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, PackedVector2Array());
return se_extension->get_vector2_buffer(p_snapshot, buffer.bufferId);
}
PackedInt32Array OpenXRSpatialComponentMesh2DList::get_indices(RID p_snapshot, int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, mesh2d_data.size(), PackedInt32Array());
const XrSpatialBufferEXT &buffer = mesh2d_data[p_index].indexBuffer;
if (buffer.bufferId == XR_NULL_SPATIAL_BUFFER_ID_EXT) {
// We don't have data (yet).
return PackedInt32Array();
}
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, PackedInt32Array());
PackedInt32Array ret;
switch (buffer.bufferType) {
case XR_SPATIAL_BUFFER_TYPE_UINT8_EXT: {
PackedByteArray data = se_extension->get_uint8_buffer(p_snapshot, buffer.bufferId);
ret.resize(data.size());
int count = ret.size();
int32_t *ptr = ret.ptrw();
for (int i = 0; i < count; i++) {
ptr[i] = data[i];
}
} break;
case XR_SPATIAL_BUFFER_TYPE_UINT16_EXT: {
Vector<uint16_t> data = se_extension->get_uint16_buffer(p_snapshot, buffer.bufferId);
ret.resize(data.size());
int count = ret.size();
int32_t *ptr = ret.ptrw();
for (int i = 0; i < count; i++) {
ptr[i] = data[i];
}
} break;
case XR_SPATIAL_BUFFER_TYPE_UINT32_EXT: {
Vector<uint32_t> data = se_extension->get_uint32_buffer(p_snapshot, buffer.bufferId);
ret.resize(data.size());
int count = ret.size();
int32_t *ptr = ret.ptrw();
for (int i = 0; i < count; i++) {
ptr[i] = data[i];
}
} break;
default: {
ERR_FAIL_V_MSG(PackedInt32Array(), "OpenXR: Unsupported buffer type for indices.");
} break;
}
return ret;
}
////////////////////////////////////////////////////////////////////////////
// Spatial component mesh3d list
void OpenXRSpatialComponentMesh3DList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform", "index"), &OpenXRSpatialComponentMesh3DList::get_transform);
ClassDB::bind_method(D_METHOD("get_mesh", "index"), &OpenXRSpatialComponentMesh3DList::get_mesh);
}
void OpenXRSpatialComponentMesh3DList::set_capacity(uint32_t p_capacity) {
mesh3d_data.resize(p_capacity);
mesh3d_list.meshCount = uint32_t(mesh3d_data.size());
mesh3d_list.meshes = mesh3d_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentMesh3DList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_MESH_3D_EXT;
}
void *OpenXRSpatialComponentMesh3DList::get_structure_data(void *p_next) {
mesh3d_list.next = p_next;
return &mesh3d_list;
}
Transform3D OpenXRSpatialComponentMesh3DList::get_transform(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, mesh3d_data.size(), Transform3D());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Transform3D());
return openxr_api->transform_from_pose(mesh3d_data[p_index].origin);
}
Ref<Mesh> OpenXRSpatialComponentMesh3DList::get_mesh(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, mesh3d_data.size(), nullptr);
// TODO implement, need to convert mesh data to Godot mesh resource
return nullptr;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialQueryResultData
void OpenXRSpatialQueryResultData::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_capacity"), &OpenXRSpatialQueryResultData::get_capacity);
ClassDB::bind_method(D_METHOD("get_entity_id", "index"), &OpenXRSpatialQueryResultData::_get_entity_id);
ClassDB::bind_method(D_METHOD("get_entity_state", "index"), &OpenXRSpatialQueryResultData::_get_entity_state);
}
void OpenXRSpatialQueryResultData::set_capacity(uint32_t p_capacity) {
entity_ids.resize(p_capacity);
entity_states.resize(p_capacity);
query_result.entityIdCapacityInput = entity_ids.size();
query_result.entityIds = entity_ids.ptrw();
query_result.entityStateCapacityInput = entity_states.size();
query_result.entityStates = entity_states.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialQueryResultData::get_component_type() const {
// This component is always included and has no type.
return XR_SPATIAL_COMPONENT_TYPE_MAX_ENUM_EXT;
}
void *OpenXRSpatialQueryResultData::get_structure_data(void *p_next) {
query_result.next = p_next;
query_result.entityIdCountOutput = 0;
query_result.entityStateCountOutput = 0;
return &query_result;
}
XrSpatialEntityIdEXT OpenXRSpatialQueryResultData::get_entity_id(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, entity_ids.size(), XR_NULL_ENTITY);
return entity_ids[p_index];
}
uint64_t OpenXRSpatialQueryResultData::_get_entity_id(int64_t p_index) const {
return (uint64_t)get_entity_id(p_index);
}
XrSpatialEntityTrackingStateEXT OpenXRSpatialQueryResultData::get_entity_state(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, entity_states.size(), XR_SPATIAL_ENTITY_TRACKING_STATE_MAX_ENUM_EXT);
return entity_states[p_index];
}
OpenXRSpatialEntityTracker::EntityTrackingState OpenXRSpatialQueryResultData::_get_entity_state(int64_t p_index) const {
return (OpenXRSpatialEntityTracker::EntityTrackingState)get_entity_state(p_index);
}
String OpenXRSpatialQueryResultData::get_entity_tracking_state_name(XrSpatialEntityTrackingStateEXT p_tracking_state) {
XR_ENUM_SWITCH(XrSpatialEntityTrackingStateEXT, p_tracking_state)
}

View file

@ -0,0 +1,230 @@
/**************************************************************************/
/* openxr_spatial_entities.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../../openxr_structure.h"
#include "../openxr_future_extension.h"
#include "scene/resources/mesh.h"
#include "servers/xr/xr_positional_tracker.h"
#define XR_NULL_ENTITY 0x7FFFFFFF
// Wrapper class for XrSpatialCapabilityConfigurationBaseHeaderEXT
class OpenXRSpatialCapabilityConfigurationBaseHeader : public RefCounted {
GDCLASS(OpenXRSpatialCapabilityConfigurationBaseHeader, RefCounted);
protected:
static void _bind_methods();
public:
virtual bool has_valid_configuration() const;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration();
GDVIRTUAL0RC(bool, _has_valid_configuration);
GDVIRTUAL0R(uint64_t, _get_configuration);
};
// Tracker for our spatial entities
class OpenXRSpatialEntityTracker : public XRPositionalTracker {
GDCLASS(OpenXRSpatialEntityTracker, XRPositionalTracker);
public:
enum EntityTrackingState {
ENTITY_TRACKING_STATE_STOPPED = XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT,
ENTITY_TRACKING_STATE_PAUSED = XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT,
ENTITY_TRACKING_STATE_TRACKING = XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT,
};
OpenXRSpatialEntityTracker();
virtual ~OpenXRSpatialEntityTracker();
void set_entity(const RID &p_entity);
RID get_entity() const;
void set_spatial_tracking_state(const XrSpatialEntityTrackingStateEXT p_state);
XrSpatialEntityTrackingStateEXT get_spatial_tracking_state() const;
protected:
static void _bind_methods();
private:
RID spatial_entity;
XrSpatialEntityTrackingStateEXT spatial_tracking_state = XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT;
void _set_spatial_tracking_state(const EntityTrackingState p_state);
EntityTrackingState _get_spatial_tracking_state() const;
};
VARIANT_ENUM_CAST(OpenXRSpatialEntityTracker::EntityTrackingState)
// Wrapper class for our spatial component data returned by discovery queries
class OpenXRSpatialComponentData : public RefCounted {
GDCLASS(OpenXRSpatialComponentData, RefCounted);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity);
virtual XrSpatialComponentTypeEXT get_component_type() const;
virtual void *get_structure_data(void *p_next);
GDVIRTUAL1(_set_capacity, uint32_t);
GDVIRTUAL0RC(uint64_t, _get_component_type);
GDVIRTUAL1RC(uint64_t, _get_structure_data, uint64_t);
};
class OpenXRSpatialComponentBounded2DList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentBounded2DList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
Transform3D get_center_pose(int64_t p_index) const;
Vector2 get_size(int64_t p_index) const;
private:
Vector<XrSpatialBounded2DDataEXT> bounded2d_data;
XrSpatialComponentBounded2DListEXT bounded2d_list = { XR_TYPE_SPATIAL_COMPONENT_BOUNDED_2D_LIST_EXT, nullptr, 0, nullptr };
};
class OpenXRSpatialComponentBounded3DList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentBounded3DList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
Transform3D get_center_pose(int64_t p_index) const;
Vector3 get_size(int64_t p_index) const;
private:
Vector<XrBoxf> bounded3d_data;
XrSpatialComponentBounded3DListEXT bounded3d_list = { XR_TYPE_SPATIAL_COMPONENT_BOUNDED_3D_LIST_EXT, nullptr, 0, nullptr };
};
class OpenXRSpatialComponentParentList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentParentList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
RID get_parent(int64_t p_index) const;
private:
Vector<XrSpatialEntityIdEXT> parent_data;
XrSpatialComponentParentListEXT parent_list = { XR_TYPE_SPATIAL_COMPONENT_PARENT_LIST_EXT, nullptr, 0, nullptr };
};
class OpenXRSpatialComponentMesh2DList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentMesh2DList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
Transform3D get_transform(int64_t p_index) const;
PackedVector2Array get_vertices(RID p_snapshot, int64_t p_index) const;
PackedInt32Array get_indices(RID p_snapshot, int64_t p_index) const;
private:
Vector<XrSpatialMeshDataEXT> mesh2d_data;
XrSpatialComponentMesh2DListEXT mesh2d_list = { XR_TYPE_SPATIAL_COMPONENT_MESH_2D_LIST_EXT, nullptr, 0, nullptr };
};
class OpenXRSpatialComponentMesh3DList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentMesh3DList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
Transform3D get_transform(int64_t p_index) const;
Ref<Mesh> get_mesh(int64_t p_index) const;
private:
Vector<XrSpatialMeshDataEXT> mesh3d_data;
XrSpatialComponentMesh3DListEXT mesh3d_list = { XR_TYPE_SPATIAL_COMPONENT_MESH_3D_LIST_EXT, nullptr, 0, nullptr };
};
class OpenXRSpatialQueryResultData : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialQueryResultData, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
int64_t get_capacity() const { return entity_ids.size(); }
XrSpatialEntityIdEXT get_entity_id(int64_t p_index) const;
XrSpatialEntityTrackingStateEXT get_entity_state(int64_t p_index) const;
static String get_entity_tracking_state_name(XrSpatialEntityTrackingStateEXT p_tracking_state);
private:
Vector<XrSpatialEntityIdEXT> entity_ids;
Vector<XrSpatialEntityTrackingStateEXT> entity_states;
XrSpatialComponentDataQueryResultEXT query_result = { XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT, nullptr, 0, 0, nullptr, 0, 0, nullptr };
uint64_t _get_entity_id(int64_t p_index) const;
OpenXRSpatialEntityTracker::EntityTrackingState _get_entity_state(int64_t p_index) const;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,217 @@
/**************************************************************************/
/* openxr_spatial_entity_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../../openxr_util.h"
#include "../openxr_extension_wrapper.h"
#include "core/templates/rid_owner.h"
#include "core/variant/typed_array.h"
#include "openxr_spatial_entities.h"
// Spatial entity extension
class OpenXRSpatialEntityExtension : public OpenXRExtensionWrapper {
GDCLASS(OpenXRSpatialEntityExtension, OpenXRExtensionWrapper);
public:
enum Capability {
CAPABILITY_PLANE_TRACKING = XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT,
CAPABILITY_MARKER_TRACKING_QR_CODE = XR_SPATIAL_CAPABILITY_MARKER_TRACKING_QR_CODE_EXT,
CAPABILITY_MARKER_TRACKING_MICRO_QR_CODE = XR_SPATIAL_CAPABILITY_MARKER_TRACKING_MICRO_QR_CODE_EXT,
CAPABILITY_MARKER_TRACKING_ARUCO_MARKER = XR_SPATIAL_CAPABILITY_MARKER_TRACKING_ARUCO_MARKER_EXT,
CAPABILITY_MARKER_TRACKING_APRIL_TAG = XR_SPATIAL_CAPABILITY_MARKER_TRACKING_APRIL_TAG_EXT,
CAPABILITY_ANCHOR = XR_SPATIAL_CAPABILITY_ANCHOR_EXT,
};
enum ComponentType {
COMPONENT_TYPE_BOUNDED_2D = XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT,
COMPONENT_TYPE_BOUNDED_3D = XR_SPATIAL_COMPONENT_TYPE_BOUNDED_3D_EXT,
COMPONENT_TYPE_PARENT = XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT,
COMPONENT_TYPE_MESH_3D = XR_SPATIAL_COMPONENT_TYPE_MESH_3D_EXT,
COMPONENT_TYPE_PLANE_ALIGNMENT = XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT,
COMPONENT_TYPE_MESH_2D = XR_SPATIAL_COMPONENT_TYPE_MESH_2D_EXT,
COMPONENT_TYPE_POLYGON_2D = XR_SPATIAL_COMPONENT_TYPE_POLYGON_2D_EXT,
COMPONENT_TYPE_PLANE_SEMANTIC_LABEL = XR_SPATIAL_COMPONENT_TYPE_PLANE_SEMANTIC_LABEL_EXT,
COMPONENT_TYPE_MARKER = XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT,
COMPONENT_TYPE_ANCHOR = XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT,
COMPONENT_TYPE_PERSISTENCE = XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,
};
static OpenXRSpatialEntityExtension *get_singleton();
OpenXRSpatialEntityExtension();
virtual ~OpenXRSpatialEntityExtension() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_instance_destroyed() override;
virtual void on_session_destroyed() override;
virtual bool on_event_polled(const XrEventDataBuffer &event) override;
bool get_active() const;
bool supports_capability(XrSpatialCapabilityEXT p_capability);
bool supports_component_type(XrSpatialCapabilityEXT p_capability, XrSpatialComponentTypeEXT p_component_type);
// Spatial contexts
Ref<OpenXRFutureResult> create_spatial_context(const TypedArray<OpenXRSpatialCapabilityConfigurationBaseHeader> &p_capability_configurations, Ref<OpenXRStructureBase> p_next, const Callable &p_user_callback);
bool get_spatial_context_ready(RID p_spatial_context) const;
void free_spatial_context(RID p_spatial_context);
XrSpatialContextEXT get_spatial_context_handle(RID p_spatial_context) const;
// Discovery query
Ref<OpenXRFutureResult> discover_spatial_entities(RID p_spatial_context, const Vector<XrSpatialComponentTypeEXT> &p_component_types, Ref<OpenXRStructureBase> p_next, const Callable &p_user_callback);
// Update query
RID update_spatial_entities(RID p_spatial_context, const LocalVector<RID> &p_entities, const LocalVector<XrSpatialComponentTypeEXT> &p_component_types, Ref<OpenXRStructureBase> p_next);
// Snapshot data
void free_spatial_snapshot(RID p_spatial_snapshot);
XrSpatialSnapshotEXT get_spatial_snapshot_handle(RID p_spatial_snapshot) const;
RID get_spatial_snapshot_context(RID p_spatial_snapshot) const;
bool query_snapshot(RID p_spatial_snapshot, const TypedArray<OpenXRSpatialComponentData> &p_component_data, Ref<OpenXRStructureBase> p_next);
// Buffers from snapshot
String get_string(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
PackedByteArray get_uint8_buffer(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
Vector<uint16_t> get_uint16_buffer(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
Vector<uint32_t> get_uint32_buffer(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
PackedFloat32Array get_float_buffer(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
PackedVector2Array get_vector2_buffer(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
PackedVector3Array get_vector3_buffer(RID p_spatial_snapshot, XrSpatialBufferIdEXT p_buffer_id) const;
// Entities
RID find_spatial_entity(XrSpatialEntityIdEXT p_entity_id) const;
RID add_spatial_entity(RID p_spatial_context, XrSpatialEntityIdEXT p_entity_id, XrSpatialEntityEXT p_entity);
RID make_spatial_entity(RID p_spatial_context, XrSpatialEntityIdEXT p_entity_id);
XrSpatialEntityIdEXT get_spatial_entity_id(RID p_entity) const;
RID get_spatial_entity_context(RID p_entity) const;
void free_spatial_entity(RID p_entity);
static String get_spatial_capability_name(XrSpatialCapabilityEXT p_capability);
static String get_spatial_component_type_name(XrSpatialComponentTypeEXT p_component_type);
static String get_spatial_feature_name(XrSpatialCapabilityFeatureEXT p_feature);
protected:
static void _bind_methods();
private:
static OpenXRSpatialEntityExtension *singleton;
bool spatial_entity_ext = false;
// Capabilities
struct SpatialEntityCapabality {
Vector<XrSpatialComponentTypeEXT> component_types;
Vector<XrSpatialCapabilityFeatureEXT> features;
};
HashMap<XrSpatialCapabilityEXT, SpatialEntityCapabality> supported_capabilities;
int capabilities_load_state = 0; // 0 = no, 1 = yes, 2 = failed
bool _load_capabilities();
bool _supports_capability(Capability p_capability);
bool _supports_component_type(Capability p_capability, ComponentType p_component_type);
// Spatial context
struct SpatialContextData {
XrSpatialContextEXT spatial_context = XR_NULL_HANDLE;
};
mutable RID_Owner<SpatialContextData> spatial_context_owner;
void _on_context_creation_ready(Ref<OpenXRFutureResult> p_future_result, const Callable &p_user_callback);
uint64_t _get_spatial_context_handle(RID p_spatial_context) const;
// Spatial query
Ref<OpenXRFutureResult> _discover_spatial_entities(RID p_spatial_context, const PackedInt64Array &p_component_types, Ref<OpenXRStructureBase> p_next, const Callable &p_callback);
void _on_discovered_spatial_entities(Ref<OpenXRFutureResult> p_future_result, RID p_discovery_spatial_context, const Callable &p_user_callback);
// Update query
RID _update_spatial_entities(RID p_spatial_context, const TypedArray<RID> &p_entities, const PackedInt64Array &p_component_types, Ref<OpenXRStructureBase> p_next);
// Snapshot data
struct SpatialSnapshotData {
RID spatial_context;
XrSpatialSnapshotEXT spatial_snapshot = XR_NULL_HANDLE;
};
mutable RID_Owner<SpatialSnapshotData> spatial_snapshot_owner;
uint64_t _get_spatial_snapshot_handle(RID p_spatial_snapshot) const;
// Buffers from snapshot
String _get_string(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
PackedByteArray _get_uint8_buffer(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
PackedInt32Array _get_uint16_buffer(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
PackedInt32Array _get_uint32_buffer(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
PackedFloat32Array _get_float_buffer(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
PackedVector2Array _get_vector2_buffer(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
PackedVector3Array _get_vector3_buffer(RID p_spatial_snapshot, uint64_t p_buffer_id) const;
// Entities
struct SpatialEntityData {
RID spatial_context;
XrSpatialEntityIdEXT entity_id = XR_NULL_ENTITY;
XrSpatialEntityEXT entity = XR_NULL_HANDLE;
};
mutable RID_Owner<SpatialEntityData> spatial_entity_owner;
RID _find_entity(uint64_t p_entity_id);
RID _add_entity(RID p_spatial_context, uint64_t p_entity_id, uint64_t p_entity);
RID _make_entity(RID p_spatial_context, uint64_t p_entity_id);
uint64_t _get_entity_id(RID p_entity) const;
// OpenXR API call wrappers
// Spatial entities
EXT_PROTO_XRRESULT_FUNC5(xrEnumerateSpatialCapabilitiesEXT, (XrInstance), instance, (XrSystemId), system_id, (uint32_t), capability_capacity_input, (uint32_t *), capability_count_output, (XrSpatialCapabilityEXT *), capabilities);
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSpatialCapabilityComponentTypesEXT, (XrInstance), instance, (XrSystemId), systemId, (XrSpatialCapabilityEXT), capability, (XrSpatialCapabilityComponentTypesEXT *), capability_components);
EXT_PROTO_XRRESULT_FUNC6(xrEnumerateSpatialCapabilityFeaturesEXT, (XrInstance), instance, (XrSystemId), systemId, (XrSpatialCapabilityEXT), capability, (uint32_t), capability_feature_capacity_input, (uint32_t *), capability_feature_count_output, (XrSpatialCapabilityFeatureEXT *), capability_features);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialContextAsyncEXT, (XrSession), session, (const XrSpatialContextCreateInfoEXT *), create_info, (XrFutureEXT *), future);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialContextCompleteEXT, (XrSession), session, (XrFutureEXT), future, (XrCreateSpatialContextCompletionEXT *), completion);
EXT_PROTO_XRRESULT_FUNC1(xrDestroySpatialContextEXT, (XrSpatialContextEXT), spatial_context);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialDiscoverySnapshotAsyncEXT, (XrSpatialContextEXT), spatial_context, (const XrSpatialDiscoverySnapshotCreateInfoEXT *), create_info, (XrFutureEXT *), future);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialDiscoverySnapshotCompleteEXT, (XrSpatialContextEXT), spatial_context, (const XrCreateSpatialDiscoverySnapshotCompletionInfoEXT *), create_snapshot_completion_info, (XrCreateSpatialDiscoverySnapshotCompletionEXT *), completion);
EXT_PROTO_XRRESULT_FUNC3(xrQuerySpatialComponentDataEXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialComponentDataQueryConditionEXT *), query_condition, (XrSpatialComponentDataQueryResultEXT *), query_result);
EXT_PROTO_XRRESULT_FUNC1(xrDestroySpatialSnapshotEXT, (XrSpatialSnapshotEXT), snapshot);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialEntityFromIdEXT, (XrSpatialContextEXT), spatial_context, (const XrSpatialEntityFromIdCreateInfoEXT *), create_info, (XrSpatialEntityEXT *), spatial_entity);
EXT_PROTO_XRRESULT_FUNC1(xrDestroySpatialEntityEXT, (XrSpatialEntityEXT), spatial_entity);
EXT_PROTO_XRRESULT_FUNC3(xrCreateSpatialUpdateSnapshotEXT, (XrSpatialContextEXT), spatial_context, (const XrSpatialUpdateSnapshotCreateInfoEXT *), createInfo, (XrSpatialSnapshotEXT *), snapshot);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferStringEXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (char *), buffer);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferUint8EXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (uint8_t *), buffer);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferUint16EXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (uint16_t *), buffer);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferUint32EXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (uint32_t *), buffer);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferFloatEXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (float *), buffer);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferVector2fEXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (XrVector2f *), buffer);
EXT_PROTO_XRRESULT_FUNC5(xrGetSpatialBufferVector3fEXT, (XrSpatialSnapshotEXT), snapshot, (const XrSpatialBufferGetInfoEXT *), info, (uint32_t), buffer_capacity_input, (uint32_t *), buffer_count_output, (XrVector3f *), buffer);
};
VARIANT_ENUM_CAST(OpenXRSpatialEntityExtension::Capability);
VARIANT_ENUM_CAST(OpenXRSpatialEntityExtension::ComponentType);

View file

@ -0,0 +1,788 @@
/**************************************************************************/
/* openxr_spatial_marker_tracking.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "openxr_spatial_marker_tracking.h"
#include "../../openxr_api.h"
#include "core/config/project_settings.h"
#include "openxr_spatial_entity_extension.h"
#include "servers/xr_server.h"
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialCapabilityConfigurationQrCode
void OpenXRSpatialCapabilityConfigurationQrCode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enabled_components"), &OpenXRSpatialCapabilityConfigurationQrCode::_get_enabled_components);
}
bool OpenXRSpatialCapabilityConfigurationQrCode::has_valid_configuration() const {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, false);
return capability->is_qrcode_supported();
}
XrSpatialCapabilityConfigurationBaseHeaderEXT *OpenXRSpatialCapabilityConfigurationQrCode::get_configuration() {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, nullptr);
if (capability->is_qrcode_supported()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Guaranteed components:
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT);
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
// Set up our enabled components.
marker_config.enabledComponentCount = enabled_components.size();
marker_config.enabledComponents = enabled_components.ptr();
// and return this.
return (XrSpatialCapabilityConfigurationBaseHeaderEXT *)&marker_config;
}
return nullptr;
}
PackedInt64Array OpenXRSpatialCapabilityConfigurationQrCode::_get_enabled_components() const {
PackedInt64Array components;
for (const XrSpatialComponentTypeEXT &component_type : enabled_components) {
components.push_back((int64_t)component_type);
}
return components;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialCapabilityConfigurationMicroQrCode
void OpenXRSpatialCapabilityConfigurationMicroQrCode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enabled_components"), &OpenXRSpatialCapabilityConfigurationMicroQrCode::_get_enabled_components);
}
bool OpenXRSpatialCapabilityConfigurationMicroQrCode::has_valid_configuration() const {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, false);
return capability->is_micro_qrcode_supported();
}
XrSpatialCapabilityConfigurationBaseHeaderEXT *OpenXRSpatialCapabilityConfigurationMicroQrCode::get_configuration() {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, nullptr);
if (capability->is_micro_qrcode_supported()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Guaranteed components:
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT);
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
// Set up our enabled components.
marker_config.enabledComponentCount = enabled_components.size();
marker_config.enabledComponents = enabled_components.ptr();
// and return this.
return (XrSpatialCapabilityConfigurationBaseHeaderEXT *)&marker_config;
}
return nullptr;
}
PackedInt64Array OpenXRSpatialCapabilityConfigurationMicroQrCode::_get_enabled_components() const {
PackedInt64Array components;
for (const XrSpatialComponentTypeEXT &component_type : enabled_components) {
components.push_back((int64_t)component_type);
}
return components;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialCapabilityConfigurationAruco
void OpenXRSpatialCapabilityConfigurationAruco::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enabled_components"), &OpenXRSpatialCapabilityConfigurationAruco::_get_enabled_components);
ClassDB::bind_method(D_METHOD("set_aruco_dict", "aruco_dict"), &OpenXRSpatialCapabilityConfigurationAruco::_set_aruco_dict);
ClassDB::bind_method(D_METHOD("get_aruco_dict"), &OpenXRSpatialCapabilityConfigurationAruco::_get_aruco_dict);
ADD_PROPERTY(PropertyInfo(Variant::INT, "aruco_dict"), "set_aruco_dict", "get_aruco_dict");
BIND_ENUM_CONSTANT(ARUCO_DICT_4X4_50);
BIND_ENUM_CONSTANT(ARUCO_DICT_4X4_100);
BIND_ENUM_CONSTANT(ARUCO_DICT_4X4_250);
BIND_ENUM_CONSTANT(ARUCO_DICT_4X4_1000);
BIND_ENUM_CONSTANT(ARUCO_DICT_5X5_50);
BIND_ENUM_CONSTANT(ARUCO_DICT_5X5_100);
BIND_ENUM_CONSTANT(ARUCO_DICT_5X5_250);
BIND_ENUM_CONSTANT(ARUCO_DICT_5X5_1000);
BIND_ENUM_CONSTANT(ARUCO_DICT_6X6_50);
BIND_ENUM_CONSTANT(ARUCO_DICT_6X6_100);
BIND_ENUM_CONSTANT(ARUCO_DICT_6X6_250);
BIND_ENUM_CONSTANT(ARUCO_DICT_6X6_1000);
BIND_ENUM_CONSTANT(ARUCO_DICT_7X7_50);
BIND_ENUM_CONSTANT(ARUCO_DICT_7X7_100);
BIND_ENUM_CONSTANT(ARUCO_DICT_7X7_250);
BIND_ENUM_CONSTANT(ARUCO_DICT_7X7_1000);
}
bool OpenXRSpatialCapabilityConfigurationAruco::has_valid_configuration() const {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, false);
return capability->is_aruco_supported();
}
XrSpatialCapabilityConfigurationBaseHeaderEXT *OpenXRSpatialCapabilityConfigurationAruco::get_configuration() {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, nullptr);
if (capability->is_aruco_supported()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Guaranteed components:
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT);
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
// Set up our enabled components.
marker_config.enabledComponentCount = enabled_components.size();
marker_config.enabledComponents = enabled_components.ptr();
// and return this.
return (XrSpatialCapabilityConfigurationBaseHeaderEXT *)&marker_config;
}
return nullptr;
}
void OpenXRSpatialCapabilityConfigurationAruco::set_aruco_dict(XrSpatialMarkerArucoDictEXT p_dict) {
marker_config.arUcoDict = p_dict;
}
void OpenXRSpatialCapabilityConfigurationAruco::_set_aruco_dict(ArucoDict p_dict) {
set_aruco_dict((XrSpatialMarkerArucoDictEXT)p_dict);
}
XrSpatialMarkerArucoDictEXT OpenXRSpatialCapabilityConfigurationAruco::get_aruco_dict() const {
return marker_config.arUcoDict;
}
OpenXRSpatialCapabilityConfigurationAruco::ArucoDict OpenXRSpatialCapabilityConfigurationAruco::_get_aruco_dict() const {
return (ArucoDict)get_aruco_dict();
}
PackedInt64Array OpenXRSpatialCapabilityConfigurationAruco::_get_enabled_components() const {
PackedInt64Array components;
for (const XrSpatialComponentTypeEXT &component_type : enabled_components) {
components.push_back((int64_t)component_type);
}
return components;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialCapabilityConfigurationAprilTag
void OpenXRSpatialCapabilityConfigurationAprilTag::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enabled_components"), &OpenXRSpatialCapabilityConfigurationAprilTag::_get_enabled_components);
ClassDB::bind_method(D_METHOD("set_april_dict", "april_dict"), &OpenXRSpatialCapabilityConfigurationAprilTag::_set_april_dict);
ClassDB::bind_method(D_METHOD("get_april_dict"), &OpenXRSpatialCapabilityConfigurationAprilTag::_get_april_dict);
ADD_PROPERTY(PropertyInfo(Variant::INT, "april_dict"), "set_april_dict", "get_april_dict");
BIND_ENUM_CONSTANT(APRIL_TAG_DICT_16H5);
BIND_ENUM_CONSTANT(APRIL_TAG_DICT_25H9);
BIND_ENUM_CONSTANT(APRIL_TAG_DICT_36H10);
BIND_ENUM_CONSTANT(APRIL_TAG_DICT_36H11);
}
bool OpenXRSpatialCapabilityConfigurationAprilTag::has_valid_configuration() const {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, false);
return capability->is_april_tag_supported();
}
XrSpatialCapabilityConfigurationBaseHeaderEXT *OpenXRSpatialCapabilityConfigurationAprilTag::get_configuration() {
OpenXRSpatialMarkerTrackingCapability *capability = OpenXRSpatialMarkerTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, nullptr);
if (capability->is_april_tag_supported()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Guaranteed components:
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT);
enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
// Set up our enabled components.
marker_config.enabledComponentCount = enabled_components.size();
marker_config.enabledComponents = enabled_components.ptr();
// and return this.
return (XrSpatialCapabilityConfigurationBaseHeaderEXT *)&marker_config;
}
return nullptr;
}
void OpenXRSpatialCapabilityConfigurationAprilTag::set_april_dict(XrSpatialMarkerAprilTagDictEXT p_dict) {
marker_config.aprilDict = p_dict;
}
void OpenXRSpatialCapabilityConfigurationAprilTag::_set_april_dict(AprilTagDict p_dict) {
set_april_dict((XrSpatialMarkerAprilTagDictEXT)p_dict);
}
XrSpatialMarkerAprilTagDictEXT OpenXRSpatialCapabilityConfigurationAprilTag::get_april_dict() const {
return marker_config.aprilDict;
}
OpenXRSpatialCapabilityConfigurationAprilTag::AprilTagDict OpenXRSpatialCapabilityConfigurationAprilTag::_get_april_dict() const {
return (AprilTagDict)get_april_dict();
}
PackedInt64Array OpenXRSpatialCapabilityConfigurationAprilTag::_get_enabled_components() const {
PackedInt64Array components;
for (const XrSpatialComponentTypeEXT &component_type : enabled_components) {
components.push_back((int64_t)component_type);
}
return components;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialComponentMarkerList
void OpenXRSpatialComponentMarkerList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_marker_type", "index"), &OpenXRSpatialComponentMarkerList::get_marker_type);
ClassDB::bind_method(D_METHOD("get_marker_id", "index"), &OpenXRSpatialComponentMarkerList::get_marker_id);
ClassDB::bind_method(D_METHOD("get_marker_data", "snapshot", "index"), &OpenXRSpatialComponentMarkerList::get_marker_data);
BIND_ENUM_CONSTANT(MARKER_TYPE_UNKNOWN);
BIND_ENUM_CONSTANT(MARKER_TYPE_QRCODE);
BIND_ENUM_CONSTANT(MARKER_TYPE_MICRO_QRCODE);
BIND_ENUM_CONSTANT(MARKER_TYPE_ARUCO);
BIND_ENUM_CONSTANT(MARKER_TYPE_APRIL_TAG);
BIND_ENUM_CONSTANT(MARKER_TYPE_MAX);
}
void OpenXRSpatialComponentMarkerList::set_capacity(uint32_t p_capacity) {
marker_data.resize(p_capacity);
marker_list.markerCount = uint32_t(marker_data.size());
marker_list.markers = marker_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentMarkerList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT;
}
void *OpenXRSpatialComponentMarkerList::get_structure_data(void *p_next) {
marker_list.next = p_next;
return &marker_list;
}
OpenXRSpatialComponentMarkerList::MarkerType OpenXRSpatialComponentMarkerList::get_marker_type(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, marker_data.size(), MARKER_TYPE_UNKNOWN);
// We can't simply cast these.
// This may give us problems in the future if we get new types through vendor extensions.
switch (marker_data[p_index].capability) {
case XR_SPATIAL_CAPABILITY_MARKER_TRACKING_QR_CODE_EXT: {
return MARKER_TYPE_QRCODE;
} break;
case XR_SPATIAL_CAPABILITY_MARKER_TRACKING_MICRO_QR_CODE_EXT: {
return MARKER_TYPE_MICRO_QRCODE;
} break;
case XR_SPATIAL_CAPABILITY_MARKER_TRACKING_ARUCO_MARKER_EXT: {
return MARKER_TYPE_ARUCO;
} break;
case XR_SPATIAL_CAPABILITY_MARKER_TRACKING_APRIL_TAG_EXT: {
return MARKER_TYPE_APRIL_TAG;
} break;
default: {
return MARKER_TYPE_UNKNOWN;
} break;
}
}
uint32_t OpenXRSpatialComponentMarkerList::get_marker_id(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, marker_data.size(), 0);
return marker_data[p_index].markerId;
}
Variant OpenXRSpatialComponentMarkerList::get_marker_data(RID p_snapshot, int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, marker_data.size(), Variant());
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, Variant());
const XrSpatialBufferEXT &data = marker_data[p_index].data;
switch (data.bufferType) {
case XR_SPATIAL_BUFFER_TYPE_STRING_EXT: {
return se_extension->get_string(p_snapshot, data.bufferId);
} break;
case XR_SPATIAL_BUFFER_TYPE_UINT8_EXT: {
return se_extension->get_uint8_buffer(p_snapshot, data.bufferId);
} break;
default: {
return Variant();
} break;
}
}
////////////////////////////////////////////////////////////////////////////
// OpenXRMarkerTracker
void OpenXRMarkerTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bounds_size", "bounds_size"), &OpenXRMarkerTracker::set_bounds_size);
ClassDB::bind_method(D_METHOD("get_bounds_size"), &OpenXRMarkerTracker::get_bounds_size);
ADD_PROPERTY(PropertyInfo(Variant::INT, "bounds_size"), "set_bounds_size", "get_bounds_size");
ClassDB::bind_method(D_METHOD("set_marker_type", "marker_type"), &OpenXRMarkerTracker::set_marker_type);
ClassDB::bind_method(D_METHOD("get_marker_type"), &OpenXRMarkerTracker::get_marker_type);
ADD_PROPERTY(PropertyInfo(Variant::INT, "marker_type"), "set_marker_type", "get_marker_type");
ClassDB::bind_method(D_METHOD("set_marker_id", "marker_id"), &OpenXRMarkerTracker::set_marker_id);
ClassDB::bind_method(D_METHOD("get_marker_id"), &OpenXRMarkerTracker::get_marker_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "marker_id"), "set_marker_id", "get_marker_id");
// As the type of marker data can vary, we can't make this a property.
ClassDB::bind_method(D_METHOD("set_marker_data", "marker_data"), &OpenXRMarkerTracker::set_marker_data);
ClassDB::bind_method(D_METHOD("get_marker_data"), &OpenXRMarkerTracker::get_marker_data);
}
void OpenXRMarkerTracker::set_bounds_size(const Vector2 &p_bounds_size) {
bounds_size = p_bounds_size;
}
Vector2 OpenXRMarkerTracker::get_bounds_size() const {
return bounds_size;
}
void OpenXRMarkerTracker::set_marker_type(OpenXRSpatialComponentMarkerList::MarkerType p_marker_type) {
marker_type = p_marker_type;
}
OpenXRSpatialComponentMarkerList::MarkerType OpenXRMarkerTracker::get_marker_type() const {
return marker_type;
}
void OpenXRMarkerTracker::set_marker_id(uint32_t p_id) {
marker_id = p_id;
}
uint32_t OpenXRMarkerTracker::get_marker_id() const {
return marker_id;
}
void OpenXRMarkerTracker::set_marker_data(const Variant &p_data) {
marker_data = p_data;
}
Variant OpenXRMarkerTracker::get_marker_data() const {
return marker_data;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialMarkerTrackingCapability
OpenXRSpatialMarkerTrackingCapability *OpenXRSpatialMarkerTrackingCapability::singleton = nullptr;
OpenXRSpatialMarkerTrackingCapability *OpenXRSpatialMarkerTrackingCapability::get_singleton() {
return singleton;
}
OpenXRSpatialMarkerTrackingCapability::OpenXRSpatialMarkerTrackingCapability() {
singleton = this;
}
OpenXRSpatialMarkerTrackingCapability::~OpenXRSpatialMarkerTrackingCapability() {
singleton = nullptr;
}
void OpenXRSpatialMarkerTrackingCapability::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_qrcode_supported"), &OpenXRSpatialMarkerTrackingCapability::is_qrcode_supported);
ClassDB::bind_method(D_METHOD("is_micro_qrcode_supported"), &OpenXRSpatialMarkerTrackingCapability::is_micro_qrcode_supported);
ClassDB::bind_method(D_METHOD("is_aruco_supported"), &OpenXRSpatialMarkerTrackingCapability::is_aruco_supported);
ClassDB::bind_method(D_METHOD("is_april_tag_supported"), &OpenXRSpatialMarkerTrackingCapability::is_april_tag_supported);
}
HashMap<String, bool *> OpenXRSpatialMarkerTrackingCapability::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
if (GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/spatial_entity/enabled") && GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/spatial_entity/enable_marker_tracking")) {
request_extensions[XR_EXT_SPATIAL_MARKER_TRACKING_EXTENSION_NAME] = &spatial_marker_tracking_ext;
}
return request_extensions;
}
void OpenXRSpatialMarkerTrackingCapability::on_session_created(const XrSession p_session) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
if (!spatial_marker_tracking_ext) {
return;
}
se_extension->connect(SNAME("spatial_discovery_recommended"), callable_mp(this, &OpenXRSpatialMarkerTrackingCapability::_on_spatial_discovery_recommended));
if (GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/spatial_entity/enable_builtin_marker_tracking")) {
// Start by creating our spatial context
_create_spatial_context();
}
}
void OpenXRSpatialMarkerTrackingCapability::on_session_destroyed() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
// Free and unregister our anchors
for (const KeyValue<XrSpatialEntityIdEXT, Ref<OpenXRMarkerTracker>> &marker_tracker : marker_trackers) {
xr_server->remove_tracker(marker_tracker.value);
}
marker_trackers.clear();
// Free our spatial context
if (spatial_context.is_valid()) {
se_extension->free_spatial_context(spatial_context);
spatial_context = RID();
}
se_extension->disconnect(SNAME("spatial_discovery_recommended"), callable_mp(this, &OpenXRSpatialMarkerTrackingCapability::_on_spatial_discovery_recommended));
}
void OpenXRSpatialMarkerTrackingCapability::on_process() {
if (!spatial_context.is_valid()) {
return;
}
// Protection against marker discovery happening too often.
if (discovery_cooldown > 0) {
discovery_cooldown--;
}
// Check if we need to start our discovery.
if (need_discovery && discovery_cooldown == 0 && !discovery_query_result.is_valid()) {
need_discovery = false;
discovery_cooldown = 60; // Set our cooldown to 60 frames, it doesn't need to be an exact science.
_start_entity_discovery();
}
// If we have markers, we do an update query to check for changed positions.
if (!marker_trackers.is_empty()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
// We want updates for all anchors
thread_local LocalVector<RID> entities;
entities.resize(marker_trackers.size());
RID *entity = entities.ptr();
for (const KeyValue<XrSpatialEntityIdEXT, Ref<OpenXRMarkerTracker>> &e : marker_trackers) {
*entity = e.value->get_entity();
entity++;
}
// We just want our anchor component
thread_local LocalVector<XrSpatialComponentTypeEXT> component_types;
component_types.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
// And we get our update snapshot, this is NOT async!
RID snapshot = se_extension->update_spatial_entities(spatial_context, entities, component_types, nullptr);
if (snapshot.is_valid()) {
_process_snapshot(snapshot, false);
}
}
}
bool OpenXRSpatialMarkerTrackingCapability::is_qrcode_supported() {
if (!spatial_marker_tracking_ext) {
return false;
}
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
return se_extension->supports_capability(XR_SPATIAL_CAPABILITY_MARKER_TRACKING_QR_CODE_EXT);
}
bool OpenXRSpatialMarkerTrackingCapability::is_micro_qrcode_supported() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
return se_extension->supports_capability(XR_SPATIAL_CAPABILITY_MARKER_TRACKING_MICRO_QR_CODE_EXT);
}
bool OpenXRSpatialMarkerTrackingCapability::is_aruco_supported() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
return se_extension->supports_capability(XR_SPATIAL_CAPABILITY_MARKER_TRACKING_ARUCO_MARKER_EXT);
}
bool OpenXRSpatialMarkerTrackingCapability::is_april_tag_supported() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
return se_extension->supports_capability(XR_SPATIAL_CAPABILITY_MARKER_TRACKING_APRIL_TAG_EXT);
}
////////////////////////////////////////////////////////////////////////////
// Discovery logic
Ref<OpenXRFutureResult> OpenXRSpatialMarkerTrackingCapability::_create_spatial_context() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
TypedArray<OpenXRSpatialCapabilityConfigurationBaseHeader> capability_configurations;
// Create our configuration objects.
// For now we enable all supported markers, will need to give some more user control over this.
if (is_qrcode_supported()) {
qrcode_configuration.instantiate();
capability_configurations.push_back(qrcode_configuration);
}
if (is_micro_qrcode_supported()) {
micro_qrcode_configuration.instantiate();
capability_configurations.push_back(micro_qrcode_configuration);
}
if (is_aruco_supported()) {
aruco_configuration.instantiate();
int aruco_dict = GLOBAL_GET_CACHED(int, "xr/openxr/extensions/spatial_entity/aruco_dict");
aruco_configuration->set_aruco_dict((XrSpatialMarkerArucoDictEXT)(XR_SPATIAL_MARKER_ARUCO_DICT_4X4_50_EXT + aruco_dict));
capability_configurations.push_back(aruco_configuration);
}
if (is_april_tag_supported()) {
april_tag_configuration.instantiate();
int april_tag_dict = GLOBAL_GET_CACHED(int, "xr/openxr/extensions/spatial_entity/april_tag_dict");
april_tag_configuration->set_april_dict((XrSpatialMarkerAprilTagDictEXT)(XR_SPATIAL_MARKER_APRIL_TAG_DICT_16H5_EXT + april_tag_dict));
capability_configurations.push_back(april_tag_configuration);
}
if (capability_configurations.is_empty()) {
print_verbose("OpenXR: There are no supported marker types. Marker tracking is not enabled.");
return nullptr;
}
return se_extension->create_spatial_context(capability_configurations, nullptr, callable_mp(this, &OpenXRSpatialMarkerTrackingCapability::_on_spatial_context_created));
}
void OpenXRSpatialMarkerTrackingCapability::_on_spatial_context_created(RID p_spatial_context) {
spatial_context = p_spatial_context;
need_discovery = true;
}
void OpenXRSpatialMarkerTrackingCapability::_on_spatial_discovery_recommended(RID p_spatial_context) {
if (p_spatial_context == spatial_context) {
// Trigger new discovery.
need_discovery = true;
}
}
Ref<OpenXRFutureResult> OpenXRSpatialMarkerTrackingCapability::_start_entity_discovery() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Already running or ran discovery, cancel/clean up.
if (discovery_query_result.is_valid()) {
discovery_query_result->cancel_future();
discovery_query_result.unref();
}
// We want both our anchor and persistence component.
Vector<XrSpatialComponentTypeEXT> component_types;
component_types.push_back(XR_SPATIAL_COMPONENT_TYPE_MARKER_EXT);
component_types.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
// Start our new snapshot.
discovery_query_result = se_extension->discover_spatial_entities(spatial_context, component_types, nullptr, callable_mp(this, &OpenXRSpatialMarkerTrackingCapability::_process_snapshot).bind(true));
return discovery_query_result;
}
void OpenXRSpatialMarkerTrackingCapability::_process_snapshot(RID p_snapshot, bool p_is_discovery) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL(openxr_api);
// Make a copy of the markers we have right now, so we know which ones to clean up.
LocalVector<XrSpatialEntityIdEXT> current_markers;
if (p_is_discovery) {
current_markers.resize(marker_trackers.size());
int m = 0;
for (const KeyValue<XrSpatialEntityIdEXT, Ref<OpenXRMarkerTracker>> &marker : marker_trackers) {
current_markers[m++] = marker.key;
}
}
// Build our component data.
TypedArray<OpenXRSpatialComponentData> component_data;
// We always need a query result data object.
Ref<OpenXRSpatialQueryResultData> query_result_data;
query_result_data.instantiate();
component_data.push_back(query_result_data);
// Add bounded2D.
Ref<OpenXRSpatialComponentBounded2DList> bounded2d_list;
bounded2d_list.instantiate();
component_data.push_back(bounded2d_list);
// Marker data list.
Ref<OpenXRSpatialComponentMarkerList> marker_list;
if (p_is_discovery) {
marker_list.instantiate();
component_data.push_back(marker_list);
}
if (se_extension->query_snapshot(p_snapshot, component_data, nullptr)) {
// Now loop through our data and update our markers.
int64_t size = query_result_data->get_capacity();
for (int64_t i = 0; i < size; i++) {
XrSpatialEntityIdEXT entity_id = query_result_data->get_entity_id(i);
XrSpatialEntityTrackingStateEXT entity_state = query_result_data->get_entity_state(i);
// Erase it from our current markers (if we have it, else this is ignored).
current_markers.erase(entity_id);
if (entity_state == XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT) {
// We should only get this status on update queries.
// We'll remove the marker.
if (marker_trackers.has(entity_id)) {
Ref<OpenXRMarkerTracker> marker_tracker = marker_trackers[entity_id];
marker_tracker->invalidate_pose(SNAME("default"));
marker_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT);
// Remove it from our XRServer.
xr_server->remove_tracker(marker_tracker);
// Remove it from our trackers.
marker_trackers.erase(entity_id);
}
} else {
// Process our entity.
bool add_to_xr_server = false;
Ref<OpenXRMarkerTracker> marker_tracker;
if (marker_trackers.has(entity_id)) {
// We know about this one already.
marker_tracker = marker_trackers[entity_id];
} else {
// Create a new anchor.
marker_tracker.instantiate();
marker_tracker->set_entity(se_extension->make_spatial_entity(se_extension->get_spatial_snapshot_context(p_snapshot), entity_id));
marker_trackers[entity_id] = marker_tracker;
add_to_xr_server = true;
}
// Handle component data.
if (entity_state == XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT) {
marker_tracker->invalidate_pose(SNAME("default"));
marker_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT);
// No further component data will be valid in this state, we need to ignore it!
} else if (entity_state == XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT) {
Transform3D transform = bounded2d_list->get_center_pose(i);
marker_tracker->set_pose(SNAME("default"), transform, Vector3(), Vector3());
marker_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT);
// Process our component data.
// Set bounds size.
marker_tracker->set_bounds_size(bounded2d_list->get_size(i));
// Set marker data.
if (p_is_discovery) {
marker_tracker->set_marker_type(marker_list->get_marker_type(i));
marker_tracker->set_marker_id(marker_list->get_marker_id(i));
marker_tracker->set_marker_data(marker_list->get_marker_data(p_snapshot, i));
}
}
if (add_to_xr_server) {
// Register with XR server.
xr_server->add_tracker(marker_tracker);
}
}
}
if (p_is_discovery) {
// Remove any markers that are no longer there...
for (const XrSpatialEntityIdEXT &entity_id : current_markers) {
if (marker_trackers.has(entity_id)) {
Ref<OpenXRMarkerTracker> marker_tracker = marker_trackers[entity_id];
// Just in case there are still references out there to this marker,
// reset some stuff.
marker_tracker->invalidate_pose(SNAME("default"));
marker_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT);
// Remove it from our XRServer.
xr_server->remove_tracker(marker_tracker);
// Remove it from our trackers.
marker_trackers.erase(entity_id);
}
}
}
}
// Now that we're done, clean up our snapshot!
se_extension->free_spatial_snapshot(p_snapshot);
// And if this was our discovery snapshot, let's reset it.
if (p_is_discovery && discovery_query_result.is_valid() && discovery_query_result->get_result_value() == p_snapshot) {
discovery_query_result.unref();
}
}

View file

@ -0,0 +1,268 @@
/**************************************************************************/
/* openxr_spatial_marker_tracking.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "openxr_spatial_entities.h"
// QrCode marker tracking capability configuration
class OpenXRSpatialCapabilityConfigurationQrCode : public OpenXRSpatialCapabilityConfigurationBaseHeader {
GDCLASS(OpenXRSpatialCapabilityConfigurationQrCode, OpenXRSpatialCapabilityConfigurationBaseHeader);
public:
virtual bool has_valid_configuration() const override;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration() override;
Vector<XrSpatialComponentTypeEXT> get_enabled_components() const { return enabled_components; }
protected:
static void _bind_methods();
private:
Vector<XrSpatialComponentTypeEXT> enabled_components;
XrSpatialCapabilityConfigurationQrCodeEXT marker_config = { XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_QR_CODE_EXT, nullptr, XR_SPATIAL_CAPABILITY_MARKER_TRACKING_QR_CODE_EXT, 0, nullptr };
PackedInt64Array _get_enabled_components() const;
};
// Micro QrCode marker tracking capability configuration
class OpenXRSpatialCapabilityConfigurationMicroQrCode : public OpenXRSpatialCapabilityConfigurationBaseHeader {
GDCLASS(OpenXRSpatialCapabilityConfigurationMicroQrCode, OpenXRSpatialCapabilityConfigurationBaseHeader);
public:
virtual bool has_valid_configuration() const override;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration() override;
Vector<XrSpatialComponentTypeEXT> get_enabled_components() const { return enabled_components; }
protected:
static void _bind_methods();
private:
Vector<XrSpatialComponentTypeEXT> enabled_components;
XrSpatialCapabilityConfigurationMicroQrCodeEXT marker_config = { XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_MICRO_QR_CODE_EXT, nullptr, XR_SPATIAL_CAPABILITY_MARKER_TRACKING_MICRO_QR_CODE_EXT, 0, nullptr };
PackedInt64Array _get_enabled_components() const;
};
// Aruco marker tracking capability configuration
class OpenXRSpatialCapabilityConfigurationAruco : public OpenXRSpatialCapabilityConfigurationBaseHeader {
GDCLASS(OpenXRSpatialCapabilityConfigurationAruco, OpenXRSpatialCapabilityConfigurationBaseHeader);
public:
enum ArucoDict {
ARUCO_DICT_4X4_50 = XR_SPATIAL_MARKER_ARUCO_DICT_4X4_50_EXT,
ARUCO_DICT_4X4_100 = XR_SPATIAL_MARKER_ARUCO_DICT_4X4_100_EXT,
ARUCO_DICT_4X4_250 = XR_SPATIAL_MARKER_ARUCO_DICT_4X4_250_EXT,
ARUCO_DICT_4X4_1000 = XR_SPATIAL_MARKER_ARUCO_DICT_4X4_1000_EXT,
ARUCO_DICT_5X5_50 = XR_SPATIAL_MARKER_ARUCO_DICT_5X5_50_EXT,
ARUCO_DICT_5X5_100 = XR_SPATIAL_MARKER_ARUCO_DICT_5X5_100_EXT,
ARUCO_DICT_5X5_250 = XR_SPATIAL_MARKER_ARUCO_DICT_5X5_250_EXT,
ARUCO_DICT_5X5_1000 = XR_SPATIAL_MARKER_ARUCO_DICT_5X5_1000_EXT,
ARUCO_DICT_6X6_50 = XR_SPATIAL_MARKER_ARUCO_DICT_6X6_50_EXT,
ARUCO_DICT_6X6_100 = XR_SPATIAL_MARKER_ARUCO_DICT_6X6_100_EXT,
ARUCO_DICT_6X6_250 = XR_SPATIAL_MARKER_ARUCO_DICT_6X6_250_EXT,
ARUCO_DICT_6X6_1000 = XR_SPATIAL_MARKER_ARUCO_DICT_6X6_1000_EXT,
ARUCO_DICT_7X7_50 = XR_SPATIAL_MARKER_ARUCO_DICT_7X7_50_EXT,
ARUCO_DICT_7X7_100 = XR_SPATIAL_MARKER_ARUCO_DICT_7X7_100_EXT,
ARUCO_DICT_7X7_250 = XR_SPATIAL_MARKER_ARUCO_DICT_7X7_250_EXT,
ARUCO_DICT_7X7_1000 = XR_SPATIAL_MARKER_ARUCO_DICT_7X7_1000_EXT,
};
virtual bool has_valid_configuration() const override;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration() override;
void set_aruco_dict(XrSpatialMarkerArucoDictEXT p_dict);
XrSpatialMarkerArucoDictEXT get_aruco_dict() const;
Vector<XrSpatialComponentTypeEXT> get_enabled_components() const { return enabled_components; }
protected:
static void _bind_methods();
private:
Vector<XrSpatialComponentTypeEXT> enabled_components;
XrSpatialCapabilityConfigurationArucoMarkerEXT marker_config = { XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ARUCO_MARKER_EXT, nullptr, XR_SPATIAL_CAPABILITY_MARKER_TRACKING_ARUCO_MARKER_EXT, 0, nullptr, XR_SPATIAL_MARKER_ARUCO_DICT_7X7_1000_EXT };
PackedInt64Array _get_enabled_components() const;
void _set_aruco_dict(ArucoDict p_dict);
ArucoDict _get_aruco_dict() const;
};
VARIANT_ENUM_CAST(OpenXRSpatialCapabilityConfigurationAruco::ArucoDict);
// April tag marker tracking capability configuration
class OpenXRSpatialCapabilityConfigurationAprilTag : public OpenXRSpatialCapabilityConfigurationBaseHeader {
GDCLASS(OpenXRSpatialCapabilityConfigurationAprilTag, OpenXRSpatialCapabilityConfigurationBaseHeader);
public:
enum AprilTagDict {
APRIL_TAG_DICT_16H5 = XR_SPATIAL_MARKER_APRIL_TAG_DICT_16H5_EXT,
APRIL_TAG_DICT_25H9 = XR_SPATIAL_MARKER_APRIL_TAG_DICT_25H9_EXT,
APRIL_TAG_DICT_36H10 = XR_SPATIAL_MARKER_APRIL_TAG_DICT_36H10_EXT,
APRIL_TAG_DICT_36H11 = XR_SPATIAL_MARKER_APRIL_TAG_DICT_36H11_EXT,
};
virtual bool has_valid_configuration() const override;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration() override;
void set_april_dict(XrSpatialMarkerAprilTagDictEXT p_dict);
XrSpatialMarkerAprilTagDictEXT get_april_dict() const;
Vector<XrSpatialComponentTypeEXT> get_enabled_components() const { return enabled_components; }
protected:
static void _bind_methods();
private:
Vector<XrSpatialComponentTypeEXT> enabled_components;
XrSpatialCapabilityConfigurationAprilTagEXT marker_config = { XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_APRIL_TAG_EXT, nullptr, XR_SPATIAL_CAPABILITY_MARKER_TRACKING_APRIL_TAG_EXT, 0, nullptr, XR_SPATIAL_MARKER_APRIL_TAG_DICT_36H11_EXT };
PackedInt64Array _get_enabled_components() const;
void _set_april_dict(AprilTagDict p_dict);
AprilTagDict _get_april_dict() const;
};
VARIANT_ENUM_CAST(OpenXRSpatialCapabilityConfigurationAprilTag::AprilTagDict);
// Marker component data
class OpenXRSpatialComponentMarkerList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentMarkerList, OpenXRSpatialComponentData);
public:
enum MarkerType {
MARKER_TYPE_UNKNOWN,
MARKER_TYPE_QRCODE,
MARKER_TYPE_MICRO_QRCODE,
MARKER_TYPE_ARUCO,
MARKER_TYPE_APRIL_TAG,
MARKER_TYPE_MAX
};
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
MarkerType get_marker_type(int64_t p_index) const;
uint32_t get_marker_id(int64_t p_index) const;
Variant get_marker_data(RID p_snapshot, int64_t p_index) const;
protected:
static void _bind_methods();
private:
Vector<XrSpatialMarkerDataEXT> marker_data;
XrSpatialComponentMarkerListEXT marker_list = { XR_TYPE_SPATIAL_COMPONENT_MARKER_LIST_EXT, nullptr, 0, nullptr };
};
VARIANT_ENUM_CAST(OpenXRSpatialComponentMarkerList::MarkerType);
// Marker tracker
class OpenXRMarkerTracker : public OpenXRSpatialEntityTracker {
GDCLASS(OpenXRMarkerTracker, OpenXRSpatialEntityTracker);
public:
void set_bounds_size(const Vector2 &p_bounds_size);
Vector2 get_bounds_size() const;
void set_marker_type(OpenXRSpatialComponentMarkerList::MarkerType p_marker_type);
OpenXRSpatialComponentMarkerList::MarkerType get_marker_type() const;
void set_marker_id(uint32_t p_id);
uint32_t get_marker_id() const;
void set_marker_data(const Variant &p_data);
Variant get_marker_data() const;
protected:
static void _bind_methods();
private:
Vector2 bounds_size;
OpenXRSpatialComponentMarkerList::MarkerType marker_type = OpenXRSpatialComponentMarkerList::MarkerType::MARKER_TYPE_UNKNOWN;
uint32_t marker_id = 0;
Variant marker_data;
};
// Marker tracking logic
class OpenXRSpatialMarkerTrackingCapability : public OpenXRExtensionWrapper {
GDCLASS(OpenXRSpatialMarkerTrackingCapability, OpenXRExtensionWrapper);
protected:
static void _bind_methods();
public:
static OpenXRSpatialMarkerTrackingCapability *get_singleton();
OpenXRSpatialMarkerTrackingCapability();
virtual ~OpenXRSpatialMarkerTrackingCapability() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_session_created(const XrSession p_session) override;
virtual void on_session_destroyed() override;
virtual void on_process() override;
bool is_qrcode_supported();
bool is_micro_qrcode_supported();
bool is_aruco_supported();
bool is_april_tag_supported();
private:
static OpenXRSpatialMarkerTrackingCapability *singleton;
bool spatial_marker_tracking_ext = false;
RID spatial_context;
bool need_discovery = false;
int discovery_cooldown = 0;
Ref<OpenXRFutureResult> discovery_query_result;
Ref<OpenXRSpatialCapabilityConfigurationQrCode> qrcode_configuration;
Ref<OpenXRSpatialCapabilityConfigurationMicroQrCode> micro_qrcode_configuration;
Ref<OpenXRSpatialCapabilityConfigurationAruco> aruco_configuration;
Ref<OpenXRSpatialCapabilityConfigurationAprilTag> april_tag_configuration;
// Discovery logic
Ref<OpenXRFutureResult> _create_spatial_context();
void _on_spatial_context_created(RID p_spatial_context);
void _on_spatial_discovery_recommended(RID p_spatial_context);
Ref<OpenXRFutureResult> _start_entity_discovery();
void _process_snapshot(RID p_snapshot, bool p_is_discovery);
// Trackers
HashMap<XrSpatialEntityIdEXT, Ref<OpenXRMarkerTracker>> marker_trackers;
};

View file

@ -0,0 +1,879 @@
/**************************************************************************/
/* openxr_spatial_plane_tracking.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "openxr_spatial_plane_tracking.h"
#include "../../openxr_api.h"
#include "core/config/project_settings.h"
#include "scene/resources/3d/box_shape_3d.h"
#include "scene/resources/3d/concave_polygon_shape_3d.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "servers/xr_server.h"
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialCapabilityConfigurationPlaneTracking
void OpenXRSpatialCapabilityConfigurationPlaneTracking::_bind_methods() {
ClassDB::bind_method(D_METHOD("supports_mesh_2d"), &OpenXRSpatialCapabilityConfigurationPlaneTracking::get_supports_mesh_2d);
ClassDB::bind_method(D_METHOD("supports_polygons"), &OpenXRSpatialCapabilityConfigurationPlaneTracking::get_supports_polygons);
ClassDB::bind_method(D_METHOD("supports_labels"), &OpenXRSpatialCapabilityConfigurationPlaneTracking::get_supports_labels);
ClassDB::bind_method(D_METHOD("get_enabled_components"), &OpenXRSpatialCapabilityConfigurationPlaneTracking::_get_enabled_components);
}
bool OpenXRSpatialCapabilityConfigurationPlaneTracking::has_valid_configuration() const {
OpenXRSpatialPlaneTrackingCapability *capability = OpenXRSpatialPlaneTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, false);
return capability->is_supported();
}
XrSpatialCapabilityConfigurationBaseHeaderEXT *OpenXRSpatialCapabilityConfigurationPlaneTracking::get_configuration() {
OpenXRSpatialPlaneTrackingCapability *capability = OpenXRSpatialPlaneTrackingCapability::get_singleton();
ERR_FAIL_NULL_V(capability, nullptr);
if (capability->is_supported()) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Guaranteed components:
plane_enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT);
plane_enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT);
// Optional components:
if (get_supports_mesh_2d()) {
plane_enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_MESH_2D_EXT);
} else if (get_supports_polygons()) {
plane_enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_POLYGON_2D_EXT);
}
if (get_supports_labels()) {
plane_enabled_components.push_back(XR_SPATIAL_COMPONENT_TYPE_PLANE_SEMANTIC_LABEL_EXT);
}
// Set up our enabled components.
plane_config.enabledComponentCount = plane_enabled_components.size();
plane_config.enabledComponents = plane_enabled_components.ptr();
// and return this.
return (XrSpatialCapabilityConfigurationBaseHeaderEXT *)&plane_config;
}
return nullptr;
}
bool OpenXRSpatialCapabilityConfigurationPlaneTracking::get_supports_mesh_2d() {
if (supports_mesh_2d == -1) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
supports_mesh_2d = se_extension->supports_component_type(XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, XR_SPATIAL_COMPONENT_TYPE_MESH_2D_EXT) ? 1 : 0;
}
return supports_mesh_2d == 1;
}
bool OpenXRSpatialCapabilityConfigurationPlaneTracking::get_supports_polygons() {
if (supports_polygons == -1) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
supports_polygons = se_extension->supports_component_type(XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, XR_SPATIAL_COMPONENT_TYPE_POLYGON_2D_EXT) ? 1 : 0;
}
return supports_polygons == 1;
}
bool OpenXRSpatialCapabilityConfigurationPlaneTracking::get_supports_labels() {
if (supports_labels == -1) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, false);
supports_labels = se_extension->supports_component_type(XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, XR_SPATIAL_COMPONENT_TYPE_PLANE_SEMANTIC_LABEL_EXT) ? 1 : 0;
}
return supports_labels == 1;
}
PackedInt64Array OpenXRSpatialCapabilityConfigurationPlaneTracking::_get_enabled_components() const {
PackedInt64Array components;
for (const XrSpatialComponentTypeEXT &component_type : plane_enabled_components) {
components.push_back((int64_t)component_type);
}
return components;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialComponentPlaneAlignmentList
void OpenXRSpatialComponentPlaneAlignmentList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_plane_alignment", "index"), &OpenXRSpatialComponentPlaneAlignmentList::_get_plane_alignment);
BIND_ENUM_CONSTANT(PLANE_ALIGNMENT_HORIZONTAL_UPWARD);
BIND_ENUM_CONSTANT(PLANE_ALIGNMENT_HORIZONTAL_DOWNWARD);
BIND_ENUM_CONSTANT(PLANE_ALIGNMENT_VERTICAL);
BIND_ENUM_CONSTANT(PLANE_ALIGNMENT_ARBITRARY);
}
void OpenXRSpatialComponentPlaneAlignmentList::set_capacity(uint32_t p_capacity) {
plane_alignment_data.resize(p_capacity);
plane_alignment_list.planeAlignmentCount = uint32_t(plane_alignment_data.size());
plane_alignment_list.planeAlignments = plane_alignment_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentPlaneAlignmentList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT;
}
void *OpenXRSpatialComponentPlaneAlignmentList::get_structure_data(void *p_next) {
plane_alignment_list.next = p_next;
return &plane_alignment_list;
}
XrSpatialPlaneAlignmentEXT OpenXRSpatialComponentPlaneAlignmentList::get_plane_alignment(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, plane_alignment_data.size(), XR_SPATIAL_PLANE_ALIGNMENT_MAX_ENUM_EXT);
return plane_alignment_data[p_index];
}
OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment OpenXRSpatialComponentPlaneAlignmentList::_get_plane_alignment(int64_t p_index) const {
return (PlaneAlignment)get_plane_alignment(p_index);
}
////////////////////////////////////////////////////////////////////////////
// Spatial component polygon2d list
void OpenXRSpatialComponentPolygon2DList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform", "index"), &OpenXRSpatialComponentPolygon2DList::get_transform);
ClassDB::bind_method(D_METHOD("get_vertices", "snapshot", "index"), &OpenXRSpatialComponentPolygon2DList::get_vertices);
}
void OpenXRSpatialComponentPolygon2DList::set_capacity(uint32_t p_capacity) {
polygon2d_data.resize(p_capacity);
polygon2d_list.polygonCount = uint32_t(polygon2d_data.size());
polygon2d_list.polygons = polygon2d_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentPolygon2DList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_POLYGON_2D_EXT;
}
void *OpenXRSpatialComponentPolygon2DList::get_structure_data(void *p_next) {
polygon2d_list.next = p_next;
return &polygon2d_list;
}
Transform3D OpenXRSpatialComponentPolygon2DList::get_transform(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, polygon2d_data.size(), Transform3D());
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL_V(openxr_api, Transform3D());
return openxr_api->transform_from_pose(polygon2d_data[p_index].origin);
}
PackedVector2Array OpenXRSpatialComponentPolygon2DList::get_vertices(RID p_snapshot, int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, polygon2d_data.size(), PackedVector2Array());
const XrSpatialBufferEXT &buffer = polygon2d_data[p_index].vertexBuffer;
if (buffer.bufferId == XR_NULL_SPATIAL_BUFFER_ID_EXT) {
// We don't have data (yet).
return PackedVector2Array();
}
ERR_FAIL_COND_V(buffer.bufferType != XR_SPATIAL_BUFFER_TYPE_VECTOR2F_EXT, PackedVector2Array());
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, PackedVector2Array());
return se_extension->get_vector2_buffer(p_snapshot, buffer.bufferId);
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialComponentPlaneSemanticLabelList
void OpenXRSpatialComponentPlaneSemanticLabelList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_plane_semantic_label", "index"), &OpenXRSpatialComponentPlaneSemanticLabelList::_get_plane_semantic_label);
BIND_ENUM_CONSTANT(PLANE_SEMANTIC_LABEL_UNCATEGORIZED);
BIND_ENUM_CONSTANT(PLANE_SEMANTIC_LABEL_FLOOR);
BIND_ENUM_CONSTANT(PLANE_SEMANTIC_LABEL_WALL);
BIND_ENUM_CONSTANT(PLANE_SEMANTIC_LABEL_CEILING);
BIND_ENUM_CONSTANT(PLANE_SEMANTIC_LABEL_TABLE);
}
void OpenXRSpatialComponentPlaneSemanticLabelList::set_capacity(uint32_t p_capacity) {
plane_semantic_label_data.resize(p_capacity);
plane_semantic_label_list.semanticLabelCount = uint32_t(plane_semantic_label_data.size());
plane_semantic_label_list.semanticLabels = plane_semantic_label_data.ptrw();
}
XrSpatialComponentTypeEXT OpenXRSpatialComponentPlaneSemanticLabelList::get_component_type() const {
return XR_SPATIAL_COMPONENT_TYPE_PLANE_SEMANTIC_LABEL_EXT;
}
void *OpenXRSpatialComponentPlaneSemanticLabelList::get_structure_data(void *p_next) {
plane_semantic_label_list.next = p_next;
return &plane_semantic_label_list;
}
XrSpatialPlaneSemanticLabelEXT OpenXRSpatialComponentPlaneSemanticLabelList::get_plane_semantic_label(int64_t p_index) const {
ERR_FAIL_INDEX_V(p_index, plane_semantic_label_data.size(), XR_SPATIAL_PLANE_SEMANTIC_LABEL_MAX_ENUM_EXT);
return plane_semantic_label_data[p_index];
}
OpenXRSpatialComponentPlaneSemanticLabelList::PlaneSemanticLabel OpenXRSpatialComponentPlaneSemanticLabelList::_get_plane_semantic_label(int64_t p_index) const {
return (PlaneSemanticLabel)get_plane_semantic_label(p_index);
}
////////////////////////////////////////////////////////////////////////////
// OpenXRPlaneTracker
void OpenXRPlaneTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bounds_size", "bounds_size"), &OpenXRPlaneTracker::set_bounds_size);
ClassDB::bind_method(D_METHOD("get_bounds_size"), &OpenXRPlaneTracker::get_bounds_size);
ADD_PROPERTY(PropertyInfo(Variant::INT, "bounds_size"), "set_bounds_size", "get_bounds_size");
ClassDB::bind_method(D_METHOD("set_plane_alignment", "plane_alignment"), &OpenXRPlaneTracker::set_plane_alignment);
ClassDB::bind_method(D_METHOD("get_plane_alignment"), &OpenXRPlaneTracker::get_plane_alignment);
ADD_PROPERTY(PropertyInfo(Variant::INT, "plane_alignment"), "set_plane_alignment", "get_plane_alignment");
ClassDB::bind_method(D_METHOD("set_plane_label", "plane_label"), &OpenXRPlaneTracker::set_plane_label);
ClassDB::bind_method(D_METHOD("get_plane_label"), &OpenXRPlaneTracker::get_plane_label);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "plane_label"), "set_plane_label", "get_plane_label");
ClassDB::bind_method(D_METHOD("set_mesh_data", "origin", "vertices", "indices"), &OpenXRPlaneTracker::set_mesh_data, DEFVAL(PackedInt32Array()));
ClassDB::bind_method(D_METHOD("clear_mesh_data"), &OpenXRPlaneTracker::clear_mesh_data);
ClassDB::bind_method(D_METHOD("get_mesh_offset"), &OpenXRPlaneTracker::get_mesh_offset);
ClassDB::bind_method(D_METHOD("get_mesh"), &OpenXRPlaneTracker::get_mesh);
ClassDB::bind_method(D_METHOD("get_shape", "thickness"), &OpenXRPlaneTracker::get_shape, DEFVAL(0.01));
ADD_SIGNAL(MethodInfo("mesh_changed"));
}
void OpenXRPlaneTracker::set_bounds_size(const Vector2 &p_bounds_size) {
if (Math::abs(bounds_size.x - p_bounds_size.x) > 0.001 || Math::abs(bounds_size.y - p_bounds_size.y) > 0.001) {
bounds_size = p_bounds_size;
if (!mesh.has_mesh_data) {
// Bounds changing only effects mesh data if we don't have polygon data.
clear_mesh_data();
emit_signal(SNAME("mesh_changed"));
}
}
}
Vector2 OpenXRPlaneTracker::get_bounds_size() const {
return bounds_size;
}
void OpenXRPlaneTracker::set_plane_alignment(OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment p_plane_alignment) {
if (plane_alignment != p_plane_alignment) {
plane_alignment = p_plane_alignment;
}
}
OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment OpenXRPlaneTracker::get_plane_alignment() const {
return plane_alignment;
}
void OpenXRPlaneTracker::set_plane_label(const String &p_plane_label) {
if (plane_label != p_plane_label) {
plane_label = p_plane_label;
// Also copy to description, should do something nicer here.
set_tracker_desc(plane_label);
}
}
String OpenXRPlaneTracker::get_plane_label() const {
return plane_label;
}
void OpenXRPlaneTracker::set_mesh_data(const Transform3D &p_origin, const PackedVector2Array &p_vertices, const PackedInt32Array &p_indices) {
if (p_vertices.size() < 3) {
if (mesh.has_mesh_data) {
clear_mesh_data();
emit_signal(SNAME("mesh_changed"));
}
} else {
bool has_changed = !mesh.has_mesh_data;
mesh.has_mesh_data = true;
mesh.origin = p_origin;
if (mesh.vertices.size() != p_vertices.size()) {
has_changed = true;
} else {
// Compare the vertices with a bit of margin, we ignore small jittering on vertices.
for (uint32_t i = 0; i < p_vertices.size() && !has_changed; i++) {
const Vector2 &a = p_vertices[i];
const Vector2 &b = mesh.vertices[i];
has_changed = (Math::abs(a.x - b.x) > 0.001) || (Math::abs(a.y - b.y) > 0.001);
}
}
if (has_changed) {
mesh.vertices = p_vertices;
}
// Q: Should we keep our indices list empty if we get polygon data
// and create different meshes/collision shapes as a result?
if (p_indices.is_empty()) {
// Assume polygon, turn into triangle strip...
int count = (p_vertices.size() - 2) * 3;
// If our vertices haven't changed and our indices are already the correct size,
// assume we don't need to rerun this.
if (has_changed || mesh.indices.size() != count) {
has_changed = true;
int offset = 1;
mesh.indices.resize(count);
int32_t *idx = mesh.indices.ptrw();
for (int i = 0; i < count; i += 3) {
idx[i + 0] = 0;
idx[i + 2] = offset++;
idx[i + 1] = offset;
}
}
} else {
if (mesh.indices.size() != p_indices.size()) {
has_changed = true;
} else {
for (uint32_t i = 0; i < p_indices.size() && !has_changed; i++) {
has_changed = mesh.indices[i] != p_indices[i];
}
}
if (has_changed) {
mesh.indices = p_indices;
}
}
if (has_changed) {
mesh.mesh.unref();
mesh.shape3d.unref();
emit_signal(SNAME("mesh_changed"));
}
}
}
void OpenXRPlaneTracker::clear_mesh_data() {
mesh.mesh.unref();
mesh.shape3d.unref();
if (mesh.has_mesh_data) {
mesh.has_mesh_data = false;
mesh.origin = Transform3D();
mesh.vertices.clear();
mesh.indices.clear();
emit_signal(SNAME("mesh_changed"));
}
}
Transform3D OpenXRPlaneTracker::get_mesh_offset() const {
Transform3D offset;
if (mesh.has_mesh_data) {
offset = mesh.origin;
Ref<XRPose> pose = get_pose(SNAME("default"));
if (pose.is_valid()) {
// Q is this offset * transform.inverse?
offset = pose->get_transform().inverse() * offset;
}
// Reference frame will already be applied to pose used on our XRNode3D but we do need to apply our scale
XRServer *xr_server = XRServer::get_singleton();
if (xr_server) {
offset.origin *= xr_server->get_world_scale();
}
}
return offset;
}
Ref<Mesh> OpenXRPlaneTracker::get_mesh() {
// We've already created this? Just return it!
if (mesh.mesh.is_valid()) {
return mesh.mesh;
}
if (mesh.has_mesh_data) {
Ref<ArrayMesh> array_mesh;
Array arr;
// We need our vertices as Vector3
PackedVector3Array vertices;
vertices.resize(mesh.vertices.size());
const Vector2 *read = mesh.vertices.ptr();
Vector3 *write = vertices.ptrw();
for (int v = 0; v < mesh.vertices.size(); v++) {
write[v] = Vector3(read[v].x, read[v].y, 0.0);
}
// Build our array with data.
arr.resize(RS::ARRAY_MAX);
arr[RS::ARRAY_VERTEX] = vertices;
arr[RS::ARRAY_INDEX] = mesh.indices;
// Create our array mesh.
array_mesh.instantiate();
array_mesh->add_surface_from_arrays(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, arr);
// Cache this.
mesh.mesh = array_mesh;
} else if (bounds_size.x > 0.0 && bounds_size.y > 0.0) {
// We can use a plane mesh here.
Ref<PlaneMesh> plane_mesh;
plane_mesh.instantiate();
plane_mesh->set_orientation(PlaneMesh::Orientation::FACE_Z);
plane_mesh->set_size(bounds_size);
// Cache this.
mesh.mesh = plane_mesh;
} else {
print_verbose("OpenXR: Can't create mesh for plane, no data.");
}
return mesh.mesh;
}
Ref<Shape3D> OpenXRPlaneTracker::get_shape(real_t p_thickness) {
// We've already created this? Just return it!
if (mesh.shape3d.is_valid()) {
return mesh.shape3d;
}
if (mesh.has_mesh_data) {
Ref<ConcavePolygonShape3D> shape;
Vector<Vector3> faces;
// Get some direct access to our data.
int isize = mesh.indices.size();
const Vector2 *vr = mesh.vertices.ptr();
const int32_t *ir = mesh.indices.ptr();
// Find our edges.
HashMap<Edge, int, Edge> edge_counts;
for (int i = 0; i < isize; i += 3) {
for (int j = 0; j < 3; j++) {
Edge e(ir[i + j], ir[i + ((j + 1) % 3)]);
edge_counts[e]++;
}
}
// Find our outer edges.
thread_local LocalVector<Edge> outer_edges;
outer_edges.clear();
for (const KeyValue<Edge, int> &e : edge_counts) {
if (e.value > 1) {
outer_edges.push_back(e.key);
}
}
// Make space for these.
faces.resize(2 * isize + 6 * outer_edges.size());
Vector3 *write = faces.ptrw();
// Add top and bottom.
for (int i = 0; i < isize; i += 3) {
Vector3 a = Vector3(vr[ir[i]].x, vr[ir[i]].y, 0.0);
Vector3 b = Vector3(vr[ir[i + 1]].x, vr[ir[i + 1]].y, 0.0);
Vector3 c = Vector3(vr[ir[i + 2]].x, vr[ir[i + 2]].y, 0.0);
*write++ = a;
*write++ = b;
*write++ = c;
a.z = -p_thickness;
b.z = -p_thickness;
c.z = -p_thickness;
*write++ = a;
*write++ = c;
*write++ = b;
}
// Add outer edges.
for (const Edge &edge : outer_edges) {
Vector3 a = Vector3(vr[edge.a].x, vr[edge.a].y, 0.0);
Vector3 b = Vector3(vr[edge.b].x, vr[edge.b].y, 0.0);
Vector3 c = b + Vector3(0.0, 0.0, -p_thickness);
Vector3 d = a + Vector3(0.0, 0.0, -p_thickness);
*write++ = a;
*write++ = b;
*write++ = c;
*write++ = a;
*write++ = c;
*write++ = d;
}
// Create our shape.
shape.instantiate();
shape->set_faces(faces);
mesh.shape3d = shape;
} else if (bounds_size.x > 0.0 && bounds_size.y > 0.0) {
// We can use a box shape here
Ref<BoxShape3D> box_shape;
box_shape.instantiate();
box_shape->set_size(Vector3(bounds_size.x, bounds_size.y, p_thickness));
mesh.shape3d = box_shape;
}
return mesh.shape3d;
}
////////////////////////////////////////////////////////////////////////////
// OpenXRSpatialPlaneTrackingCapability
OpenXRSpatialPlaneTrackingCapability *OpenXRSpatialPlaneTrackingCapability::singleton = nullptr;
OpenXRSpatialPlaneTrackingCapability *OpenXRSpatialPlaneTrackingCapability::get_singleton() {
return singleton;
}
OpenXRSpatialPlaneTrackingCapability::OpenXRSpatialPlaneTrackingCapability() {
singleton = this;
}
OpenXRSpatialPlaneTrackingCapability::~OpenXRSpatialPlaneTrackingCapability() {
singleton = nullptr;
}
void OpenXRSpatialPlaneTrackingCapability::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_supported"), &OpenXRSpatialPlaneTrackingCapability::is_supported);
}
HashMap<String, bool *> OpenXRSpatialPlaneTrackingCapability::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
if (GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/spatial_entity/enabled") && GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/spatial_entity/enable_plane_tracking")) {
request_extensions[XR_EXT_SPATIAL_PLANE_TRACKING_EXTENSION_NAME] = &spatial_plane_tracking_ext;
}
return request_extensions;
}
void OpenXRSpatialPlaneTrackingCapability::on_session_created(const XrSession p_session) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
if (!spatial_plane_tracking_ext) {
return;
}
spatial_plane_tracking_supported = se_extension->supports_capability(XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT);
if (!spatial_plane_tracking_supported) {
// Supported by XR runtime but not by device? We're done.
return;
}
se_extension->connect(SNAME("spatial_discovery_recommended"), callable_mp(this, &OpenXRSpatialPlaneTrackingCapability::_on_spatial_discovery_recommended));
if (GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/spatial_entity/enable_builtin_plane_detection")) {
// Start by creating our spatial context
_create_spatial_context();
}
}
void OpenXRSpatialPlaneTrackingCapability::on_session_destroyed() {
if (!spatial_plane_tracking_supported) {
return;
}
spatial_plane_tracking_supported = false;
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
// Free and unregister our anchors
for (const KeyValue<XrSpatialEntityIdEXT, Ref<OpenXRPlaneTracker>> &plane_tracker : plane_trackers) {
xr_server->remove_tracker(plane_tracker.value);
}
plane_trackers.clear();
// Free our spatial context
if (spatial_context.is_valid()) {
se_extension->free_spatial_context(spatial_context);
spatial_context = RID();
}
se_extension->disconnect(SNAME("spatial_discovery_recommended"), callable_mp(this, &OpenXRSpatialPlaneTrackingCapability::_on_spatial_discovery_recommended));
}
void OpenXRSpatialPlaneTrackingCapability::on_process() {
if (!spatial_context.is_valid()) {
return;
}
// Protection against plane discovery happening too often.
if (discovery_cooldown > 0) {
discovery_cooldown--;
}
// Check if we need to start our discovery.
if (need_discovery && discovery_cooldown == 0 && !discovery_query_result.is_valid()) {
need_discovery = false;
discovery_cooldown = 60; // Set our cooldown to 60 frames, it doesn't need to be an exact science.
_start_entity_discovery();
}
}
bool OpenXRSpatialPlaneTrackingCapability::is_supported() {
return spatial_plane_tracking_supported;
}
////////////////////////////////////////////////////////////////////////////
// Discovery logic
Ref<OpenXRFutureResult> OpenXRSpatialPlaneTrackingCapability::_create_spatial_context() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
TypedArray<OpenXRSpatialCapabilityConfigurationBaseHeader> capability_configurations;
// Create our configuration objects.
plane_configuration.instantiate();
capability_configurations.push_back(plane_configuration);
return se_extension->create_spatial_context(capability_configurations, nullptr, callable_mp(this, &OpenXRSpatialPlaneTrackingCapability::_on_spatial_context_created));
}
void OpenXRSpatialPlaneTrackingCapability::_on_spatial_context_created(RID p_spatial_context) {
spatial_context = p_spatial_context;
need_discovery = true;
}
void OpenXRSpatialPlaneTrackingCapability::_on_spatial_discovery_recommended(RID p_spatial_context) {
if (p_spatial_context == spatial_context) {
// Trigger new discovery.
need_discovery = true;
}
}
Ref<OpenXRFutureResult> OpenXRSpatialPlaneTrackingCapability::_start_entity_discovery() {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL_V(se_extension, nullptr);
// Already running or ran discovery, cancel/clean up.
if (discovery_query_result.is_valid()) {
WARN_PRINT("OpenXR: Starting new discovery before previous discovery has been processed!");
discovery_query_result->cancel_future();
discovery_query_result.unref();
}
// Start our new snapshot.
discovery_query_result = se_extension->discover_spatial_entities(spatial_context, plane_configuration->get_enabled_components(), nullptr, callable_mp(this, &OpenXRSpatialPlaneTrackingCapability::_process_snapshot));
return discovery_query_result;
}
void OpenXRSpatialPlaneTrackingCapability::_process_snapshot(RID p_snapshot) {
OpenXRSpatialEntityExtension *se_extension = OpenXRSpatialEntityExtension::get_singleton();
ERR_FAIL_NULL(se_extension);
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
ERR_FAIL_NULL(openxr_api);
// Make a copy of the planes we have right now, so we know which ones to clean up.
LocalVector<XrSpatialEntityIdEXT> current_planes;
current_planes.resize(plane_trackers.size());
int p = 0;
for (const KeyValue<XrSpatialEntityIdEXT, Ref<OpenXRPlaneTracker>> &plane : plane_trackers) {
current_planes[p++] = plane.key;
}
// Build our component data
TypedArray<OpenXRSpatialComponentData> component_data;
// We always need a query result data object
Ref<OpenXRSpatialQueryResultData> query_result_data;
query_result_data.instantiate();
component_data.push_back(query_result_data);
// Add bounded2D
Ref<OpenXRSpatialComponentBounded2DList> bounded2d_list;
bounded2d_list.instantiate();
component_data.push_back(bounded2d_list);
// Plane alignment list
Ref<OpenXRSpatialComponentPlaneAlignmentList> alignment_list;
alignment_list.instantiate();
component_data.push_back(alignment_list);
Ref<OpenXRSpatialComponentMesh2DList> mesh2d_list;
Ref<OpenXRSpatialComponentPolygon2DList> poly2d_list;
if (plane_configuration->get_supports_mesh_2d()) {
mesh2d_list.instantiate();
component_data.push_back(mesh2d_list);
} else if (plane_configuration->get_supports_polygons()) {
poly2d_list.instantiate();
component_data.push_back(poly2d_list);
}
// Plane semantic label
Ref<OpenXRSpatialComponentPlaneSemanticLabelList> label_list;
if (plane_configuration->get_supports_labels()) {
label_list.instantiate();
component_data.push_back(label_list);
}
if (se_extension->query_snapshot(p_snapshot, component_data, nullptr)) {
// Now loop through our data and update our anchors.
// Q we're assuming entity ID, size and state size are equal, is there ever a situation where they would not be?
int64_t size = query_result_data->get_capacity();
for (int64_t i = 0; i < size; i++) {
XrSpatialEntityIdEXT entity_id = query_result_data->get_entity_id(i);
XrSpatialEntityTrackingStateEXT entity_state = query_result_data->get_entity_state(i);
// Erase it from our current planes (if we have it, else this is ignored).
current_planes.erase(entity_id);
if (entity_state == XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT) {
// We should only get this status on updates as a prelude to needing to remove this marker.
// So we just update the status.
if (plane_trackers.has(entity_id)) {
Ref<OpenXRPlaneTracker> plane_tracker = plane_trackers[entity_id];
plane_tracker->invalidate_pose(SNAME("default"));
plane_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT);
}
} else {
// Process our entity
bool add_to_xr_server = false;
Ref<OpenXRPlaneTracker> plane_tracker;
if (plane_trackers.has(entity_id)) {
// We know about this one already
plane_tracker = plane_trackers[entity_id];
} else {
// Create a new anchor
plane_tracker.instantiate();
plane_tracker->set_entity(se_extension->make_spatial_entity(se_extension->get_spatial_snapshot_context(p_snapshot), entity_id));
plane_trackers[entity_id] = plane_tracker;
add_to_xr_server = true;
}
// Handle component data
if (entity_state == XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT) {
plane_tracker->invalidate_pose(SNAME("default"));
plane_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT);
// No further component data will be valid in this state, we need to ignore it!
} else if (entity_state == XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT) {
Transform3D transform = bounded2d_list->get_center_pose(i);
plane_tracker->set_pose(SNAME("default"), transform, Vector3(), Vector3());
plane_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT);
// Process our component data.
plane_tracker->set_bounds_size(bounded2d_list->get_size(i));
plane_tracker->set_plane_alignment((OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment)alignment_list->get_plane_alignment(i));
if (mesh2d_list.is_valid()) {
plane_tracker->set_mesh_data(mesh2d_list->get_transform(i), mesh2d_list->get_vertices(p_snapshot, i), mesh2d_list->get_indices(p_snapshot, i));
} else if (poly2d_list.is_valid()) {
plane_tracker->set_mesh_data(poly2d_list->get_transform(i), poly2d_list->get_vertices(p_snapshot, i));
} else {
// Just in case we set this before.
plane_tracker->clear_mesh_data();
}
if (label_list.is_valid()) {
switch (label_list->get_plane_semantic_label(i)) {
case XR_SPATIAL_PLANE_SEMANTIC_LABEL_UNCATEGORIZED_EXT: {
plane_tracker->set_plane_label("Uncategorized plane");
} break;
case XR_SPATIAL_PLANE_SEMANTIC_LABEL_FLOOR_EXT: {
plane_tracker->set_plane_label("Floor plane");
} break;
case XR_SPATIAL_PLANE_SEMANTIC_LABEL_WALL_EXT: {
plane_tracker->set_plane_label("Wall plane");
} break;
case XR_SPATIAL_PLANE_SEMANTIC_LABEL_CEILING_EXT: {
plane_tracker->set_plane_label("Ceiling plane");
} break;
case XR_SPATIAL_PLANE_SEMANTIC_LABEL_TABLE_EXT: {
plane_tracker->set_plane_label("Table plane");
} break;
default: {
plane_tracker->set_plane_label("Unknown plane");
} break;
}
}
}
if (add_to_xr_server) {
// Register with XR server
xr_server->add_tracker(plane_tracker);
}
}
}
// Remove any planes that are no longer there...
for (const XrSpatialEntityIdEXT &entity_id : current_planes) {
if (plane_trackers.has(entity_id)) {
Ref<OpenXRPlaneTracker> plane_tracker = plane_trackers[entity_id];
// Just in case there are still references out there to this marker,
// reset some stuff.
plane_tracker->invalidate_pose(SNAME("default"));
plane_tracker->set_spatial_tracking_state(XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT);
// Remove it from our XRServer
xr_server->remove_tracker(plane_tracker);
// Remove it from our trackers
plane_trackers.erase(entity_id);
}
}
}
// Now that we're done, clean up our snapshot!
se_extension->free_spatial_snapshot(p_snapshot);
// And if this was our discovery snapshot, lets reset it
if (discovery_query_result.is_valid() && discovery_query_result->get_result_value() == p_snapshot) {
discovery_query_result.unref();
}
}

View file

@ -0,0 +1,254 @@
/**************************************************************************/
/* openxr_spatial_plane_tracking.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "openxr_spatial_entities.h"
#include "openxr_spatial_entity_extension.h"
#include "scene/resources/3d/shape_3d.h"
// Plane tracking capability configuration
class OpenXRSpatialCapabilityConfigurationPlaneTracking : public OpenXRSpatialCapabilityConfigurationBaseHeader {
GDCLASS(OpenXRSpatialCapabilityConfigurationPlaneTracking, OpenXRSpatialCapabilityConfigurationBaseHeader);
public:
virtual bool has_valid_configuration() const override;
virtual XrSpatialCapabilityConfigurationBaseHeaderEXT *get_configuration() override;
bool get_supports_mesh_2d();
bool get_supports_polygons();
bool get_supports_labels();
Vector<XrSpatialComponentTypeEXT> get_enabled_components() const { return plane_enabled_components; }
protected:
static void _bind_methods();
private:
int supports_mesh_2d = -1;
int supports_polygons = -1;
int supports_labels = -1;
Vector<XrSpatialComponentTypeEXT> plane_enabled_components;
XrSpatialCapabilityConfigurationPlaneTrackingEXT plane_config = { XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_PLANE_TRACKING_EXT, nullptr, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, 0, nullptr };
PackedInt64Array _get_enabled_components() const;
};
// Plane alignment component data
class OpenXRSpatialComponentPlaneAlignmentList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentPlaneAlignmentList, OpenXRSpatialComponentData);
public:
enum PlaneAlignment {
PLANE_ALIGNMENT_HORIZONTAL_UPWARD = XR_SPATIAL_PLANE_ALIGNMENT_HORIZONTAL_UPWARD_EXT,
PLANE_ALIGNMENT_HORIZONTAL_DOWNWARD = XR_SPATIAL_PLANE_ALIGNMENT_HORIZONTAL_DOWNWARD_EXT,
PLANE_ALIGNMENT_VERTICAL = XR_SPATIAL_PLANE_ALIGNMENT_VERTICAL_EXT,
PLANE_ALIGNMENT_ARBITRARY = XR_SPATIAL_PLANE_ALIGNMENT_ARBITRARY_EXT,
};
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
XrSpatialPlaneAlignmentEXT get_plane_alignment(int64_t p_index) const;
protected:
static void _bind_methods();
private:
Vector<XrSpatialPlaneAlignmentEXT> plane_alignment_data;
XrSpatialComponentPlaneAlignmentListEXT plane_alignment_list = { XR_TYPE_SPATIAL_COMPONENT_PLANE_ALIGNMENT_LIST_EXT, nullptr, 0, nullptr };
PlaneAlignment _get_plane_alignment(int64_t p_index) const;
};
VARIANT_ENUM_CAST(OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment);
class OpenXRSpatialComponentPolygon2DList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentPolygon2DList, OpenXRSpatialComponentData);
protected:
static void _bind_methods();
public:
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
Transform3D get_transform(int64_t p_index) const;
PackedVector2Array get_vertices(RID p_snapshot, int64_t p_index) const;
private:
Vector<XrSpatialPolygon2DDataEXT> polygon2d_data;
XrSpatialComponentPolygon2DListEXT polygon2d_list = { XR_TYPE_SPATIAL_COMPONENT_POLYGON_2D_LIST_EXT, nullptr, 0, nullptr };
};
// Plane semantic label component data.
class OpenXRSpatialComponentPlaneSemanticLabelList : public OpenXRSpatialComponentData {
GDCLASS(OpenXRSpatialComponentPlaneSemanticLabelList, OpenXRSpatialComponentData);
public:
enum PlaneSemanticLabel {
PLANE_SEMANTIC_LABEL_UNCATEGORIZED = XR_SPATIAL_PLANE_SEMANTIC_LABEL_UNCATEGORIZED_EXT,
PLANE_SEMANTIC_LABEL_FLOOR = XR_SPATIAL_PLANE_SEMANTIC_LABEL_FLOOR_EXT,
PLANE_SEMANTIC_LABEL_WALL = XR_SPATIAL_PLANE_SEMANTIC_LABEL_WALL_EXT,
PLANE_SEMANTIC_LABEL_CEILING = XR_SPATIAL_PLANE_SEMANTIC_LABEL_CEILING_EXT,
PLANE_SEMANTIC_LABEL_TABLE = XR_SPATIAL_PLANE_SEMANTIC_LABEL_TABLE_EXT,
};
virtual void set_capacity(uint32_t p_capacity) override;
virtual XrSpatialComponentTypeEXT get_component_type() const override;
virtual void *get_structure_data(void *p_next) override;
XrSpatialPlaneSemanticLabelEXT get_plane_semantic_label(int64_t p_index) const;
protected:
static void _bind_methods();
private:
Vector<XrSpatialPlaneSemanticLabelEXT> plane_semantic_label_data;
XrSpatialComponentPlaneSemanticLabelListEXT plane_semantic_label_list = { XR_TYPE_SPATIAL_COMPONENT_PLANE_SEMANTIC_LABEL_LIST_EXT, nullptr, 0, nullptr };
PlaneSemanticLabel _get_plane_semantic_label(int64_t p_index) const;
};
VARIANT_ENUM_CAST(OpenXRSpatialComponentPlaneSemanticLabelList::PlaneSemanticLabel);
// Plane tracker
class OpenXRPlaneTracker : public OpenXRSpatialEntityTracker {
GDCLASS(OpenXRPlaneTracker, OpenXRSpatialEntityTracker);
public:
void set_bounds_size(const Vector2 &p_bounds_size);
Vector2 get_bounds_size() const;
void set_plane_alignment(OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment p_plane_alignment);
OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment get_plane_alignment() const;
void set_plane_label(const String &p_plane_label);
String get_plane_label() const;
void set_mesh_data(const Transform3D &p_origin, const PackedVector2Array &p_vertices, const PackedInt32Array &p_indices = PackedInt32Array());
void clear_mesh_data();
Transform3D get_mesh_offset() const;
Ref<Mesh> get_mesh();
Ref<Shape3D> get_shape(real_t p_thickness = 0.01);
protected:
static void _bind_methods();
private:
Vector2 bounds_size;
OpenXRSpatialComponentPlaneAlignmentList::PlaneAlignment plane_alignment = OpenXRSpatialComponentPlaneAlignmentList::PLANE_ALIGNMENT_HORIZONTAL_UPWARD;
String plane_label;
// Mesh data (if we have this)
struct MeshData {
bool has_mesh_data = false;
Transform3D origin;
PackedVector2Array vertices;
PackedInt32Array indices;
Ref<Mesh> mesh;
Ref<Shape3D> shape3d;
} mesh;
struct Edge {
int32_t a;
int32_t b;
static _FORCE_INLINE_ uint32_t hash(const Edge &p_edge) {
uint32_t h = hash_murmur3_one_32(p_edge.a);
return hash_murmur3_one_32(p_edge.b, h);
}
bool operator==(const Edge &p_edge) const {
return (a == p_edge.a && b == p_edge.b);
}
Edge(int32_t p_a = 0, int32_t p_b = 0) {
a = p_a;
b = p_b;
if (a < b) {
SWAP(a, b);
}
}
};
};
// Plane tracking logic
class OpenXRSpatialPlaneTrackingCapability : public OpenXRExtensionWrapper {
GDCLASS(OpenXRSpatialPlaneTrackingCapability, OpenXRExtensionWrapper);
protected:
static void _bind_methods();
public:
static OpenXRSpatialPlaneTrackingCapability *get_singleton();
OpenXRSpatialPlaneTrackingCapability();
virtual ~OpenXRSpatialPlaneTrackingCapability() override;
virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_session_created(const XrSession p_session) override;
virtual void on_session_destroyed() override;
virtual void on_process() override;
bool is_supported();
private:
static OpenXRSpatialPlaneTrackingCapability *singleton;
bool spatial_plane_tracking_ext = false;
bool spatial_plane_tracking_supported = false;
RID spatial_context;
bool need_discovery = false;
int discovery_cooldown = 0;
Ref<OpenXRFutureResult> discovery_query_result;
Ref<OpenXRSpatialCapabilityConfigurationPlaneTracking> plane_configuration;
// Discovery logic
Ref<OpenXRFutureResult> _create_spatial_context();
void _on_spatial_context_created(RID p_spatial_context);
void _on_spatial_discovery_recommended(RID p_spatial_context);
Ref<OpenXRFutureResult> _start_entity_discovery();
void _process_snapshot(RID p_snapshot);
// Trackers
HashMap<XrSpatialEntityIdEXT, Ref<OpenXRPlaneTracker>> plane_trackers;
};

View file

@ -307,20 +307,23 @@ String OpenXRAPI::get_default_action_map_resource_name() {
return name; return name;
} }
String OpenXRAPI::get_error_string(XrResult result) const { String OpenXRAPI::get_error_string(XrResult p_result) const {
if (XR_SUCCEEDED(result)) { if (XR_SUCCEEDED(p_result)) {
return String("Succeeded"); return String("Succeeded");
} }
if (instance == XR_NULL_HANDLE) { if (instance == XR_NULL_HANDLE) {
Array args = { Variant(result) }; Array args = { Variant(p_result) };
return String("Error code {0}").format(args); return String("Error code {0}").format(args);
} }
char resultString[XR_MAX_RESULT_STRING_SIZE]; char resultString[XR_MAX_RESULT_STRING_SIZE];
xrResultToString(instance, result, resultString); XrResult result = xrResultToString(instance, p_result, resultString);
if (XR_FAILED(result)) {
return String(resultString); XR_ENUM_SWITCH(XrResult, p_result);
} else {
return String(resultString);
}
} }
String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const { String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
@ -2833,6 +2836,22 @@ Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) {
return Transform3D(basis, origin); return Transform3D(basis, origin);
} }
XrPosef OpenXRAPI::pose_from_transform(const Transform3D &p_transform) {
XrPosef pose;
Quaternion q(p_transform.basis);
pose.orientation.x = q.x;
pose.orientation.y = q.y;
pose.orientation.z = q.z;
pose.orientation.w = q.w;
pose.position.x = p_transform.origin.x;
pose.position.y = p_transform.origin.y;
pose.position.z = p_transform.origin.z;
return pose;
}
template <typename T> template <typename T>
XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) { XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) {
XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;

View file

@ -430,6 +430,7 @@ public:
// helper method to convert an XrPosef to a Transform3D // helper method to convert an XrPosef to a Transform3D
Transform3D transform_from_pose(const XrPosef &p_pose); Transform3D transform_from_pose(const XrPosef &p_pose);
XrPosef pose_from_transform(const Transform3D &p_transform);
// helper method to get a valid Transform3D from an openxr space location // helper method to get a valid Transform3D from an openxr space location
XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform); XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform);

View file

@ -0,0 +1,83 @@
/**************************************************************************/
/* openxr_structure.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "openxr_structure.h"
void OpenXRStructureBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_structure_type"), &OpenXRStructureBase::_get_structure_type);
ClassDB::bind_method(D_METHOD("set_next", "entity"), &OpenXRStructureBase::set_next);
ClassDB::bind_method(D_METHOD("get_next"), &OpenXRStructureBase::get_next);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "next", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRStructureBase"), "set_next", "get_next");
GDVIRTUAL_BIND(_get_header, "next");
}
void OpenXRStructureBase::set_next(const Ref<OpenXRStructureBase> p_next) {
next = p_next;
}
Ref<OpenXRStructureBase> OpenXRStructureBase::get_next() const {
return next;
}
void *OpenXRStructureBase::get_header(void *p_next) {
void *n = p_next;
if (get_next().is_valid()) {
n = get_next()->get_header(p_next);
}
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_get_header, (uint64_t)n, pointer)) {
return reinterpret_cast<void *>(pointer);
}
return n;
}
XrStructureType OpenXRStructureBase::get_structure_type() {
// By default we call get_header to get the structure type so we have a guaranteed implementation.
// The first member of our header is always the structure type, so this works:
XrStructureType *header = (XrStructureType *)get_header();
if (header == nullptr) {
// Header can return nullptr for valid reasons, so we do not error here!
return XR_TYPE_UNKNOWN;
} else {
return *header;
}
}
// Return structure type as uint64_t to GDScript
uint64_t OpenXRStructureBase::_get_structure_type() {
return (uint64_t)get_structure_type();
}

View file

@ -0,0 +1,76 @@
/**************************************************************************/
/* openxr_structure.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/object/gdvirtual.gen.inc"
#include "core/object/ref_counted.h"
#include "openxr_util.h"
#include "util.h"
// Base class for XrStructureType based headers
class OpenXRStructureBase : public RefCounted {
GDCLASS(OpenXRStructureBase, RefCounted);
public:
/*
* get_header should return a pointer to a proper XrStructureType structure.
* The pointer should remain valid as long as this object is not destructed.
*
* This function should be implemented based on the following template:
* void *get_header(void *p_next = nullptr) {
* my_xr_struct.type = XR_TYPE_XYZ;
* if (get_next().is_valid()) {
* my_xr_struct.next = get_next()->get_header(p_next);
* } else {
* my_xr_struct.next = p_next
* }
*
* // add further setup of the struct here
*
* return &my_xr_struct;
* }
*/
virtual void *get_header(void *p_next = nullptr);
virtual XrStructureType get_structure_type();
void set_next(const Ref<OpenXRStructureBase> p_next);
Ref<OpenXRStructureBase> get_next() const;
GDVIRTUAL1R(uint64_t, _get_header, uint64_t);
protected:
static void _bind_methods();
private:
Ref<OpenXRStructureBase> next;
uint64_t _get_structure_type();
};

View file

@ -34,13 +34,9 @@
#include <openxr/openxr_reflection.h> #include <openxr/openxr_reflection.h>
#define XR_ENUM_CASE_STR(name, val) \ String OpenXRUtil::get_result_string(XrResult p_result){
case name: \ XR_ENUM_SWITCH(XrResult, p_result)
return #name; }
#define XR_ENUM_SWITCH(enumType, var) \
switch (var) { \
XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) default : return "Unknown " #enumType ": " + String::num_int64(int64_t(var)); \
}
String OpenXRUtil::get_view_configuration_name(XrViewConfigurationType p_view_configuration){ String OpenXRUtil::get_view_configuration_name(XrViewConfigurationType p_view_configuration){
XR_ENUM_SWITCH(XrViewConfigurationType, p_view_configuration) XR_ENUM_SWITCH(XrViewConfigurationType, p_view_configuration)
@ -78,7 +74,105 @@ String OpenXRUtil::make_xr_version_string(XrVersion p_version) {
return version; return version;
} }
// Based on the OpenXR xr_linear.h private header, so we can still link against String OpenXRUtil::get_handle_as_hex_string(void *p_handle) {
String hex;
if (p_handle == XR_NULL_HANDLE) {
return "null";
}
uint64_t handle = (uint64_t)p_handle;
while (handle != 0) {
uint8_t a = handle & 0x0F;
uint8_t b = (handle & 0xF0) >> 4;
handle = handle >> 8;
if (a < 10) {
hex = (a + '0') + hex;
} else {
hex = (a + 'a' - 10) + hex;
}
if (b < 10) {
hex = (b + '0') + hex;
} else {
hex = (b + 'a' - 10) + hex;
}
}
return "0x" + hex;
}
String OpenXRUtil::string_from_xruuid(const XrUuid &xr_uuid) {
String ret;
bool non_zero = false;
for (int i = 0; i < XR_UUID_SIZE; i++) {
non_zero |= xr_uuid.data[i] != 0;
char a = xr_uuid.data[i] & 0xF0 >> 4;
char b = xr_uuid.data[i] & 0x0F;
if (a < 10) {
ret += '0' + a;
} else {
ret += 'a' + a - 10;
}
if (b < 10) {
ret += '0' + b;
} else {
ret += 'a' + b - 10;
}
}
if (non_zero) {
return ret;
} else {
return "";
}
}
XrUuid OpenXRUtil::xruuid_from_string(const String &p_uuid) {
XrUuid new_uuid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int len = p_uuid.length();
if (len == 0) {
return new_uuid;
} else if (len != (2 * XR_UUID_SIZE)) {
WARN_PRINT("OpenXR: Unexpected UUID length: " + String::num_int64(len) + " != " + String::num_int64(2 * XR_UUID_SIZE));
}
int j = 0;
for (int i = 0; i < XR_UUID_SIZE; i++) {
uint8_t val = 0;
// 2 chars per byte.
for (int k = 0; k < 2; k++) {
if (j < len) {
val <<= 4;
char32_t c = p_uuid[j++];
if (c >= '0' && c <= '9') {
val += uint8_t(c - '0');
} else if (c >= 'a' && c <= 'f') {
val += uint8_t(10 + c - 'a');
} else if (c >= 'A' && c <= 'F') {
val += uint8_t(10 + c - 'A');
} else {
WARN_PRINT("OpenXR: Unexpected character in UUID: " + String::num_int64(c));
}
}
}
new_uuid.data[i] = val;
}
return new_uuid;
}
// Copied from OpenXR xr_linear.h private header, so we can still link against
// system-provided packages without relying on our `thirdparty` code. // system-provided packages without relying on our `thirdparty` code.
// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 The Khronos Group Inc.

View file

@ -33,9 +33,19 @@
#include "core/string/ustring.h" #include "core/string/ustring.h"
#include <openxr/openxr.h> #include <openxr/openxr.h>
#include <openxr/openxr_reflection.h>
#define XR_ENUM_CASE_STR(name, val) \
case name: \
return #name;
#define XR_ENUM_SWITCH(enumType, var) \
switch (var) { \
XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) default : return "Unknown " #enumType ": " + String::num_int64(int64_t(var)); \
}
class OpenXRUtil { class OpenXRUtil {
public: public:
static String get_result_string(XrResult p_result);
static String get_view_configuration_name(XrViewConfigurationType p_view_configuration); static String get_view_configuration_name(XrViewConfigurationType p_view_configuration);
static String get_reference_space_name(XrReferenceSpaceType p_reference_space); static String get_reference_space_name(XrReferenceSpaceType p_reference_space);
static String get_structure_type_name(XrStructureType p_structure_type); static String get_structure_type_name(XrStructureType p_structure_type);
@ -43,6 +53,9 @@ public:
static String get_action_type_name(XrActionType p_action_type); static String get_action_type_name(XrActionType p_action_type);
static String get_environment_blend_mode_name(XrEnvironmentBlendMode p_blend_mode); static String get_environment_blend_mode_name(XrEnvironmentBlendMode p_blend_mode);
static String make_xr_version_string(XrVersion p_version); static String make_xr_version_string(XrVersion p_version);
static String get_handle_as_hex_string(void *p_handle);
static String string_from_xruuid(const XrUuid &xr_uuid);
static XrUuid xruuid_from_string(const String &p_uuid);
// Copied from OpenXR xr_linear.h private header, so we can still link against // Copied from OpenXR xr_linear.h private header, so we can still link against
// system-provided packages without relying on our `thirdparty` code. // system-provided packages without relying on our `thirdparty` code.

View file

@ -75,6 +75,11 @@
#include "extensions/openxr_valve_analog_threshold_extension.h" #include "extensions/openxr_valve_analog_threshold_extension.h"
#include "extensions/openxr_visibility_mask_extension.h" #include "extensions/openxr_visibility_mask_extension.h"
#include "extensions/openxr_wmr_controller_extension.h" #include "extensions/openxr_wmr_controller_extension.h"
#include "extensions/spatial_entities/openxr_spatial_entity_extension.h"
#include "extensions/spatial_entities/openxr_spatial_anchor.h"
#include "extensions/spatial_entities/openxr_spatial_marker_tracking.h"
#include "extensions/spatial_entities/openxr_spatial_plane_tracking.h"
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
#include "editor/openxr_editor_plugin.h" #include "editor/openxr_editor_plugin.h"
@ -168,6 +173,23 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
OpenXRAPI::register_extension_wrapper(render_model_extension); OpenXRAPI::register_extension_wrapper(render_model_extension);
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRRenderModelExtension", render_model_extension)); Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRRenderModelExtension", render_model_extension));
// Register spatial entity extensions
OpenXRSpatialEntityExtension *spatial_entity_extension = memnew(OpenXRSpatialEntityExtension);
OpenXRAPI::register_extension_wrapper(spatial_entity_extension);
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRSpatialEntityExtension", spatial_entity_extension));
OpenXRSpatialAnchorCapability *anchor_capability = memnew(OpenXRSpatialAnchorCapability);
OpenXRAPI::register_extension_wrapper(anchor_capability);
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRSpatialAnchorCapability", anchor_capability));
OpenXRSpatialPlaneTrackingCapability *plane_tracking_capability = memnew(OpenXRSpatialPlaneTrackingCapability);
OpenXRAPI::register_extension_wrapper(plane_tracking_capability);
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRSpatialPlaneTrackingCapability", plane_tracking_capability));
OpenXRSpatialMarkerTrackingCapability *marker_tracking_capability = memnew(OpenXRSpatialMarkerTrackingCapability);
OpenXRAPI::register_extension_wrapper(marker_tracking_capability);
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRSpatialMarkerTrackingCapability", marker_tracking_capability));
// register gated extensions // register gated extensions
if (int(GLOBAL_GET("xr/openxr/extensions/debug_utils")) > 0) { if (int(GLOBAL_GET("xr/openxr/extensions/debug_utils")) > 0) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRDebugUtilsExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRDebugUtilsExtension));
@ -246,6 +268,39 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(OpenXRRenderModel); GDREGISTER_CLASS(OpenXRRenderModel);
GDREGISTER_CLASS(OpenXRRenderModelManager); GDREGISTER_CLASS(OpenXRRenderModelManager);
GDREGISTER_CLASS(OpenXRSpatialEntityExtension);
GDREGISTER_VIRTUAL_CLASS(OpenXRSpatialEntityTracker);
GDREGISTER_CLASS(OpenXRAnchorTracker);
GDREGISTER_CLASS(OpenXRPlaneTracker);
GDREGISTER_CLASS(OpenXRMarkerTracker);
GDREGISTER_VIRTUAL_CLASS(OpenXRStructureBase);
GDREGISTER_VIRTUAL_CLASS(OpenXRSpatialCapabilityConfigurationBaseHeader);
GDREGISTER_CLASS(OpenXRSpatialCapabilityConfigurationAnchor);
GDREGISTER_CLASS(OpenXRSpatialCapabilityConfigurationQrCode);
GDREGISTER_CLASS(OpenXRSpatialCapabilityConfigurationMicroQrCode);
GDREGISTER_CLASS(OpenXRSpatialCapabilityConfigurationAruco);
GDREGISTER_CLASS(OpenXRSpatialCapabilityConfigurationAprilTag);
GDREGISTER_CLASS(OpenXRSpatialContextPersistenceConfig);
GDREGISTER_CLASS(OpenXRSpatialCapabilityConfigurationPlaneTracking);
GDREGISTER_VIRTUAL_CLASS(OpenXRSpatialComponentData);
GDREGISTER_CLASS(OpenXRSpatialComponentBounded2DList);
GDREGISTER_CLASS(OpenXRSpatialComponentBounded3DList);
GDREGISTER_CLASS(OpenXRSpatialComponentParentList);
GDREGISTER_CLASS(OpenXRSpatialComponentMesh2DList);
GDREGISTER_CLASS(OpenXRSpatialComponentMesh3DList);
GDREGISTER_CLASS(OpenXRSpatialComponentPlaneAlignmentList);
GDREGISTER_CLASS(OpenXRSpatialComponentPolygon2DList);
GDREGISTER_CLASS(OpenXRSpatialComponentPlaneSemanticLabelList);
GDREGISTER_CLASS(OpenXRSpatialComponentMarkerList);
GDREGISTER_CLASS(OpenXRSpatialQueryResultData);
GDREGISTER_CLASS(OpenXRSpatialComponentAnchorList);
GDREGISTER_CLASS(OpenXRSpatialComponentPersistenceList);
GDREGISTER_CLASS(OpenXRSpatialAnchorCapability);
GDREGISTER_CLASS(OpenXRSpatialPlaneTrackingCapability);
GDREGISTER_CLASS(OpenXRSpatialMarkerTrackingCapability);
XRServer *xr_server = XRServer::get_singleton(); XRServer *xr_server = XRServer::get_singleton();
if (xr_server) { if (xr_server) {
openxr_interface.instantiate(); openxr_interface.instantiate();