Skip to content

Commit f7d194b

Browse files
committed
Implement XR_ANDROID_device_anchor_persistence_extension
1 parent d1da3fc commit f7d194b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2215
-10
lines changed

doc_classes/OpenXRAndroidAnchorTracker.xml

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<description>
77
An anchor tracker (from [code]XR_ANDROID_trackables[/code]).
88

9-
[OpenXRAndroidAnchorTracker]s can be created by [method OpenXRAndroidTrackablesExtension.create_anchor_tracker].
10-
All newly created [OpenXRAndroidAnchorTracker]s have up-to-date state, as in, no need to call [method get_location_flags] with [code]update == true[/code].
9+
[OpenXRAndroidAnchorTracker]s can be created by [method OpenXRAndroidTrackablesExtension.create_anchor_tracker] and [method OpenXRAndroidDeviceAnchorPersistenceExtension.create_persisted_anchor_tracker].
10+
All newly created [OpenXRAndroidAnchorTracker]s have up-to-date state, as in, no need to call [method get_persist_state] and/or [method get_location_flags] with [code]update == true[/code].
1111
When an [OpenXRAndroidAnchorTracker] is created by [method OpenXRAndroidTrackablesExtension.create_anchor_tracker], the [code]trackable[/code] parameter can be set to either [code]null[/code] or a plane [OpenXRAndroidTracker].
1212
The [OpenXRAndroidAnchorTracker] is called a "spatial anchor" when created with a [code]null[/code] [OpenXRAndroidTracker].
1313
The [OpenXRAndroidAnchorTracker] is called a "plane anchor" when created with a plane [OpenXRAndroidTracker].
@@ -42,10 +42,45 @@
4242
See [method get_location_flags] for documentation for [param update].
4343
</description>
4444
</method>
45+
<method name="get_persist_state">
46+
<return type="int" enum="OpenXRAndroidAnchorTracker.PersistState" />
47+
<param index="0" name="update" type="bool" default="false" />
48+
<description>
49+
Get the [enum OpenXRAndroidAnchorTracker.PersistState].
50+
If [param update] is [code]false[/code], then get the cached persist state.
51+
If [param update] is [code]true[/code], then query the xr runtime for the latest persist state, which may be identical to the cached persist state.
52+
If the new persist state changed from the cached value, the cached value is updated and [signal persist_state_changed] is emitted.
53+
</description>
54+
</method>
55+
<method name="get_persist_uuid" qualifiers="const">
56+
<return type="StringName" />
57+
<description>
58+
Get the persisted anchor uuid, represented as a [StringName].
59+
The returned [StringName] is non-empty if this anchor tracker is persisting or persisted. See also [method get_persist_state] to get the actual persisted state.
60+
The returned [StringName] is empty if this anchor tracker is not persisted.
61+
</description>
62+
</method>
4563
<method name="get_tracker" qualifiers="const">
4664
<return type="OpenXRAndroidTracker" />
4765
<description>
4866
Return the [OpenXRAndroidTracker] that this [OpenXRAndroidAnchorTracker] was created with.
67+
This method always returns [code]null[/code] for [OpenXRAndroidAnchorTracker]s created with [method OpenXRAndroidDeviceAnchorPersistenceExtension.create_persisted_anchor_tracker], even if the original anchor was created with an [OpenXRAndroidTracker].
68+
</description>
69+
</method>
70+
<method name="persist">
71+
<return type="bool" />
72+
<description>
73+
Persist this anchor tracker if it isn't already.
74+
Returns true if the anchor tracker was persisted successfully, or it was already persisted.
75+
NOTE: it takes some time for the xr runtime to persist an anchor tracker (usually less than a second, but sometimes longer). Connect to [signal persist_state_changed] to be notified when this tracker is persisting.
76+
</description>
77+
</method>
78+
<method name="unpersist">
79+
<return type="bool" />
80+
<description>
81+
Unpersist this anchor tracker if it isn't already.
82+
Returns true if the anchor tracker was unpersisted successfully, or it was already unpersisted.
83+
NOTE: it takes some time for the xr runtime to unpersist an anchor tracker (usually less than a second, but sometimes longer). Connect to [signal persist_state_changed] to be notified when this tracker is unpersisted.
4984
</description>
5085
</method>
5186
</methods>
@@ -56,6 +91,11 @@
5691
This signal is not emitted when a location's pose changes, however this tracker's [code]default[/code] pose is modified (and consequently its signal is also emitted) when the location transform changes.
5792
</description>
5893
</signal>
94+
<signal name="persist_state_changed">
95+
<description>
96+
Signal emitted when the persist state changes, which can be retrieved with [method get_persist_state].
97+
</description>
98+
</signal>
5999
</signals>
60100
<constants>
61101
<constant name="LOCATION_FLAGS_ORIENTATION_VALID" value="1" enum="LocationFlags" is_bitfield="true">
@@ -75,5 +115,17 @@
75115
<constant name="LOCATION_FLAGS_MAX" value="8" enum="LocationFlags" is_bitfield="true">
76116
The maximum flag bit.
77117
</constant>
118+
<constant name="PERSIST_STATE_NOT_REQUESTED" value="0" enum="PersistState">
119+
The anchor tracker has not requested to be persisted.
120+
</constant>
121+
<constant name="PERSIST_STATE_PENDING" value="1" enum="PersistState">
122+
The anchor tracker requested to be persisted, but is not persisted yet.
123+
</constant>
124+
<constant name="PERSIST_STATE_PERSISTED" value="2" enum="PersistState">
125+
The anchor tracker is persisted.
126+
</constant>
127+
<constant name="PERSIST_STATE_ERROR" value="3" enum="PersistState">
128+
An error occurred when persisting the anchor tracker.
129+
</constant>
78130
</constants>
79131
</class>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="OpenXRAndroidDeviceAnchorPersistenceExtension" inherits="OpenXRExtensionWrapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
3+
<brief_description>
4+
Implementation for creating and handling persisted anchor trackers (from [code]XR_ANDROID_device_anchor_persistence[/code]).
5+
</brief_description>
6+
<description>
7+
Implementation for creating and handling persisted anchor trackers (from [code]XR_ANDROID_device_anchor_persistence[/code]).
8+
See also [OpenXRAndroidTrackablesExtension].
9+
</description>
10+
<tutorials>
11+
</tutorials>
12+
<methods>
13+
<method name="create_persisted_anchor_tracker">
14+
<return type="OpenXRAndroidAnchorTracker" />
15+
<param index="0" name="uuid" type="StringName" />
16+
<description>
17+
Create a [OpenXRAndroidAnchorTracker] from a persisted [param uuid].
18+
Repeat calls to [method create_persisted_anchor_tracker] with the same [param uuid], without unpersisting, will return the same [OpenXRAndroidAnchorTracker] instance.
19+
[param uuid] could have come from [method get_all_persisted_anchors], [method persist_anchor_tracker], or from a cache that an app may have stored in a previous session.
20+
</description>
21+
</method>
22+
<method name="get_all_persisted_anchors">
23+
<return type="StringName[]" />
24+
<description>
25+
Retrieve an [Array] of persisted anchor uuids, as [StringName]s, that have been previously persisted with [method persist_anchor_tracker] by the app.
26+
Persisted anchors are returned even after restarting the app or rebooting the device, as long as the anchor was never unpersisted (see [method unpersist_anchor_tracker]).
27+
Persisted anchors from other apps are not returned.
28+
See also [method get_persisted_anchor_trackers].
29+
</description>
30+
</method>
31+
<method name="get_anchor_tracker_persist_state" qualifiers="const">
32+
<return type="int" enum="OpenXRAndroidAnchorTracker.PersistState" />
33+
<param index="0" name="anchor_tracker" type="OpenXRAndroidAnchorTracker" />
34+
<param index="1" name="update" type="bool" default="false" />
35+
<description>
36+
Convenience function to turn this:
37+
[codeblock]
38+
var persist_state := OpenXRAndroidAnchorTracker.PERSIST_STATE_NOT_REQUESTED
39+
if anchor_tracker:
40+
persist_state = OpenXRAndroidDeviceAnchorPersistenceExtension.get_anchor_tracker_persist_state_uuid(anchor_tracker.get_persist_uuid(), update)
41+
# or: persist_state = anchor_tracker.get_persist_state(update)
42+
[/codeblock]
43+
Into:
44+
[codeblock]
45+
var persist_state := OpenXRAndroidDeviceAnchorPersistenceExtension.get_anchor_tracker_persist_state(anchor_tracker, update)
46+
[/codeblock]
47+
See also [method OpenXRAndroidAnchorTracker.get_persist_state]
48+
</description>
49+
</method>
50+
<method name="get_anchor_tracker_persist_state_uuid">
51+
<return type="int" enum="OpenXRAndroidAnchorTracker.PersistState" />
52+
<param index="0" name="uuid" type="StringName" />
53+
<param index="1" name="update" type="bool" default="false" />
54+
<description>
55+
If a [OpenXRAndroidAnchorTracker] instance was already created for [param uuid] (via [method create_persisted_anchor_tracker]), then [method OpenXRAndroidAnchorTracker.get_persist_state] is called.
56+
Otherwise, the persist state is found from the [param uuid] and [param update] is ignored.
57+
</description>
58+
</method>
59+
<method name="get_persisted_anchor_trackers" qualifiers="const">
60+
<return type="OpenXRAndroidAnchorTracker[]" />
61+
<description>
62+
Retrieve all [OpenXRAndroidAnchorTracker]s that have been created from persisted anchor trackers since the last time the app was restarted.
63+
The number of anchor trackers returned by this function will always be less than, or equal to, the number of persisted anchor uuids returned by [method get_all_persisted_anchors].
64+
</description>
65+
</method>
66+
<method name="persist_anchor_tracker" qualifiers="const">
67+
<return type="bool" />
68+
<param index="0" name="anchor_tracker" type="OpenXRAndroidAnchorTracker" />
69+
<description>
70+
Convenience function to turn this:
71+
[codeblock]
72+
var persisted := anchor_tracker &amp;&amp; anchor_tracker.persist()
73+
[/codeblock]
74+
Into:
75+
[codeblock]
76+
var persisted := OpenXRAndroidDeviceAnchorPersistenceExtension.persist_anchor_tracker(anchor_tracker)
77+
[/codeblock]
78+
See also [method OpenXRAndroidAnchorTracker.persist]
79+
</description>
80+
</method>
81+
<method name="unpersist_anchor_tracker" qualifiers="const">
82+
<return type="bool" />
83+
<param index="0" name="anchor_tracker" type="OpenXRAndroidAnchorTracker" />
84+
<description>
85+
Convenience function to turn this:
86+
[codeblock]
87+
var unpersisted := anchor_tracker &amp;&amp; anchor_tracker.unpersist()
88+
[/codeblock]
89+
Into:
90+
[codeblock]
91+
var unpersisted := OpenXRAndroidDeviceAnchorPersistenceExtension.unpersist_anchor_tracker(anchor_tracker)
92+
[/codeblock]
93+
See also [method OpenXRAndroidAnchorTracker.unpersist] for information about persisting.
94+
</description>
95+
</method>
96+
<method name="unpersist_anchor_uuid">
97+
<return type="bool" />
98+
<param index="0" name="uuid" type="StringName" />
99+
<description>
100+
Unpersists a persisted [param uuid].
101+
The [OpenXRAndroidAnchorTracker] created from [param uuid], if any, will automatically be updated.
102+
See also [method OpenXRAndroidAnchorTracker.unpersist] for information about unpersisting.
103+
</description>
104+
</method>
105+
</methods>
106+
</class>

doc_classes/OpenXRAndroidTrackablesExtension.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
<method name="update_anchor_trackers">
106106
<return type="void" />
107107
<description>
108-
Update all anchor trackers; updating their pose (see [method OpenXRAndroidAnchorTracker.get_location_pose]).
108+
Update all anchor trackers; updating their pose and persist state (see [method OpenXRAndroidAnchorTracker.get_persist_state] and [method OpenXRAndroidAnchorTracker.get_location_pose]).
109109
This API is called automatically by default (see [method set_anchor_tracker_update_cooldown]).
110110
</description>
111111
</method>

plugin/src/main/cpp/classes/openxr_android_anchor_tracker.cpp

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "classes/openxr_android_anchor_tracker.h"
3232
#include <godot_cpp/classes/open_xrapi_extension.hpp>
3333

34+
#include "extensions/openxr_android_device_anchor_persistence_extension.h"
3435
#include "extensions/openxr_android_trackables_extension.h"
3536
#include "godot_cpp/core/class_db.hpp"
3637
#include "godot_cpp/core/error_macros.hpp"
@@ -42,24 +43,27 @@ using namespace godot;
4243
OpenXRAndroidAnchorTracker::OpenXRAndroidAnchorTracker() {}
4344
OpenXRAndroidAnchorTracker::~OpenXRAndroidAnchorTracker() {}
4445

45-
Ref<OpenXRAndroidAnchorTracker> OpenXRAndroidAnchorTracker::create(XrSpace p_xrspace, Ref<OpenXRAndroidTracker> p_tracker) {
46+
Ref<OpenXRAndroidAnchorTracker> OpenXRAndroidAnchorTracker::create(XrSpace p_xrspace, const StringName &p_persist_uuid, const XrUuidEXT &p_persist_xruuid, Ref<OpenXRAndroidTracker> p_tracker) {
4647
Ref<OpenXRAndroidAnchorTracker> ret;
4748
ret.instantiate();
4849
ret->space = p_xrspace;
50+
ret->persist_uuid = p_persist_uuid;
4951
ret->tracker = p_tracker;
5052
ret->location = create_empty_location();
5153
ret->set_tracker_type(XRServer::TRACKER_ANCHOR);
5254
ret->set_tracker_name(String("openxr/androidxr/anchor_tracker/") + String::num_uint64(OpenXRAndroidTrackablesExtension::get_next_tracker_id()));
55+
memcpy(ret->persist_xruuid.data, p_persist_xruuid.data, XR_UUID_SIZE * sizeof(decltype(XrUuid::data[0])));
5356

5457
// Ensure its cached state is sync'd with the xr runtime, just so the caller doesn't have to
55-
// explicitly remember to call "get_location/etc" with
58+
// explicitly remember to call "get_persist_state/get_location/etc" with
5659
// "p_update == true".
5760
ret->update();
5861

5962
return ret;
6063
}
6164

6265
void OpenXRAndroidAnchorTracker::update() {
66+
_update_persist_state();
6367
_update_location(true);
6468
}
6569

@@ -81,6 +85,45 @@ Transform3D OpenXRAndroidAnchorTracker::get_location_pose(bool p_update) {
8185
return location_pose;
8286
}
8387

88+
bool OpenXRAndroidAnchorTracker::persist() {
89+
OpenXRAndroidDeviceAnchorPersistenceExtension *wrapper = OpenXRAndroidDeviceAnchorPersistenceExtension::get_singleton();
90+
ERR_FAIL_NULL_V(wrapper, false);
91+
92+
bool ret = wrapper->persist_xranchor(this, persist_uuid, persist_xruuid);
93+
94+
// NOTE: unlike unpersist(), persist() changes the persist state immediately. However it is
95+
// (likely) "persist pending" (rather than "persisted").
96+
// When ret == false, ensure the state remains consistent with the xr runtime.
97+
_update_persist_state();
98+
99+
return ret;
100+
}
101+
102+
StringName OpenXRAndroidAnchorTracker::get_persist_uuid() const {
103+
return persist_uuid;
104+
}
105+
106+
OpenXRAndroidAnchorTracker::PersistState OpenXRAndroidAnchorTracker::get_persist_state(bool p_update) {
107+
if (p_update) {
108+
_update_persist_state();
109+
}
110+
111+
return persist_state;
112+
}
113+
114+
bool OpenXRAndroidAnchorTracker::unpersist() {
115+
OpenXRAndroidDeviceAnchorPersistenceExtension *wrapper = OpenXRAndroidDeviceAnchorPersistenceExtension::get_singleton();
116+
ERR_FAIL_NULL_V(wrapper, PERSIST_STATE_NOT_REQUESTED);
117+
118+
bool ret = wrapper->unpersist_xranchor(persist_uuid, persist_xruuid);
119+
120+
// NOTE: like persist(), unpersist() does not change the state immediately (it is likely still "persisted").
121+
// Regardless, ensure our persist state is accurate.
122+
_update_persist_state();
123+
124+
return ret;
125+
}
126+
84127
void OpenXRAndroidAnchorTracker::_bind_methods() {
85128
ClassDB::bind_method(D_METHOD("get_tracker"), &OpenXRAndroidAnchorTracker::get_tracker);
86129
ADD_SIGNAL(MethodInfo("location_flags_changed"));
@@ -92,6 +135,16 @@ void OpenXRAndroidAnchorTracker::_bind_methods() {
92135
BIND_BITFIELD_FLAG(LOCATION_FLAGS_ORIENTATION_TRACKED);
93136
BIND_BITFIELD_FLAG(LOCATION_FLAGS_POSITION_TRACKED);
94137
BIND_BITFIELD_FLAG(LOCATION_FLAGS_MAX);
138+
139+
ClassDB::bind_method(D_METHOD("persist"), &OpenXRAndroidAnchorTracker::persist);
140+
ClassDB::bind_method(D_METHOD("get_persist_uuid"), &OpenXRAndroidAnchorTracker::get_persist_uuid);
141+
ClassDB::bind_method(D_METHOD("get_persist_state", "update"), &OpenXRAndroidAnchorTracker::get_persist_state, DEFVAL(false));
142+
ClassDB::bind_method(D_METHOD("unpersist"), &OpenXRAndroidAnchorTracker::unpersist);
143+
BIND_ENUM_CONSTANT(PERSIST_STATE_NOT_REQUESTED);
144+
BIND_ENUM_CONSTANT(PERSIST_STATE_PENDING);
145+
BIND_ENUM_CONSTANT(PERSIST_STATE_PERSISTED);
146+
BIND_ENUM_CONSTANT(PERSIST_STATE_ERROR);
147+
ADD_SIGNAL(MethodInfo("persist_state_changed"));
95148
}
96149

97150
bool OpenXRAndroidAnchorTracker::get_xranchor_space_location(XrSpace p_xrspace, XrSpaceLocation &o_xrspace_location) {
@@ -179,3 +232,19 @@ void OpenXRAndroidAnchorTracker::_update_location(bool p_update) {
179232

180233
set_pose(StringName("default"), location_pose, Vector3(), Vector3(), confidence);
181234
}
235+
236+
void OpenXRAndroidAnchorTracker::_update_persist_state() {
237+
OpenXRAndroidDeviceAnchorPersistenceExtension *wrapper = OpenXRAndroidDeviceAnchorPersistenceExtension::get_singleton();
238+
ERR_FAIL_NULL(wrapper);
239+
240+
OpenXRAndroidAnchorTracker::PersistState new_persist_state = wrapper->get_xranchor_persist_state(persist_uuid, persist_xruuid);
241+
if (new_persist_state == PERSIST_STATE_NOT_REQUESTED) {
242+
persist_uuid = StringName{};
243+
memset(persist_xruuid.data, 0, XR_UUID_SIZE * sizeof(decltype(XrUuid::data[0])));
244+
}
245+
246+
if (new_persist_state != persist_state) {
247+
persist_state = new_persist_state;
248+
emit_signal("persist_state_changed");
249+
}
250+
}

0 commit comments

Comments
 (0)