Skip to content

Commit e64452c

Browse files
authored
Add a developer-facing API for interacting with scene anchors (#107)
1 parent 41b7eec commit e64452c

27 files changed

+2203
-172
lines changed

Diff for: common/src/main/cpp/classes/openxr_fb_scene_manager.cpp

+391
Large diffs are not rendered by default.
+340
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
/**************************************************************************/
2+
/* openxr_fb_spatial_entity.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT XR */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2022-present Godot XR contributors (see CONTRIBUTORS.md) */
9+
/* */
10+
/* Permission is hereby granted, free of charge, to any person obtaining */
11+
/* a copy of this software and associated documentation files (the */
12+
/* "Software"), to deal in the Software without restriction, including */
13+
/* without limitation the rights to use, copy, modify, merge, publish, */
14+
/* distribute, sublicense, and/or sell copies of the Software, and to */
15+
/* permit persons to whom the Software is furnished to do so, subject to */
16+
/* the following conditions: */
17+
/* */
18+
/* The above copyright notice and this permission notice shall be */
19+
/* included in all copies or substantial portions of the Software. */
20+
/* */
21+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
22+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
23+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
24+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
25+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
26+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
27+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
28+
/**************************************************************************/
29+
30+
#include "classes/openxr_fb_spatial_entity.h"
31+
32+
#include <godot_cpp/classes/box_mesh.hpp>
33+
#include <godot_cpp/classes/box_shape3d.hpp>
34+
#include <godot_cpp/classes/collision_shape3d.hpp>
35+
#include <godot_cpp/classes/mesh_instance3d.hpp>
36+
#include <godot_cpp/classes/plane_mesh.hpp>
37+
38+
#include "extensions/openxr_fb_spatial_entity_extension_wrapper.h"
39+
#include "extensions/openxr_fb_spatial_entity_container_extension_wrapper.h"
40+
#include "extensions/openxr_fb_scene_extension_wrapper.h"
41+
42+
using namespace godot;
43+
44+
void OpenXRFbSpatialEntity::_bind_methods() {
45+
ClassDB::bind_method(D_METHOD("get_uuid"), &OpenXRFbSpatialEntity::get_uuid);
46+
47+
ClassDB::bind_method(D_METHOD("get_supported_components"), &OpenXRFbSpatialEntity::get_supported_components);
48+
ClassDB::bind_method(D_METHOD("is_component_supported", "component"), &OpenXRFbSpatialEntity::is_component_supported);
49+
ClassDB::bind_method(D_METHOD("is_component_enabled", "component"), &OpenXRFbSpatialEntity::is_component_enabled);
50+
ClassDB::bind_method(D_METHOD("set_component_enabled", "component"), &OpenXRFbSpatialEntity::set_component_enabled);
51+
52+
ClassDB::bind_method(D_METHOD("get_semantic_labels"), &OpenXRFbSpatialEntity::get_semantic_labels);
53+
ClassDB::bind_method(D_METHOD("get_room_layout"), &OpenXRFbSpatialEntity::get_room_layout);
54+
ClassDB::bind_method(D_METHOD("get_contained_uuids"), &OpenXRFbSpatialEntity::get_contained_uuids);
55+
ClassDB::bind_method(D_METHOD("get_bounding_box_2d"), &OpenXRFbSpatialEntity::get_bounding_box_2d);
56+
ClassDB::bind_method(D_METHOD("get_bounding_box_3d"), &OpenXRFbSpatialEntity::get_bounding_box_3d);
57+
ClassDB::bind_method(D_METHOD("get_boundary_2d"), &OpenXRFbSpatialEntity::get_boundary_2d);
58+
59+
ClassDB::bind_method(D_METHOD("track"), &OpenXRFbSpatialEntity::track);
60+
ClassDB::bind_method(D_METHOD("untrack"), &OpenXRFbSpatialEntity::untrack);
61+
ClassDB::bind_method(D_METHOD("is_tracked"), &OpenXRFbSpatialEntity::is_tracked);
62+
63+
ClassDB::bind_method(D_METHOD("create_mesh_instance"), &OpenXRFbSpatialEntity::create_mesh_instance);
64+
ClassDB::bind_method(D_METHOD("create_collision_shape"), &OpenXRFbSpatialEntity::create_collision_shape);
65+
66+
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uuid", PROPERTY_HINT_NONE, ""), "", "get_uuid");
67+
68+
BIND_ENUM_CONSTANT(STORAGE_LOCAL);
69+
BIND_ENUM_CONSTANT(STORAGE_CLOUD);
70+
71+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_LOCATABLE);
72+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_STORABLE);
73+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SHARABLE);
74+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_BOUNDED_2D);
75+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_BOUNDED_3D);
76+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SEMANTIC_LABELS);
77+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_ROOM_LAYOUT);
78+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_CONTAINER);
79+
BIND_ENUM_CONSTANT(COMPONENT_TYPE_TRIANGLE_MESH);
80+
81+
ADD_SIGNAL(MethodInfo("openxr_fb_spatial_entity_set_component_enabled_completed", PropertyInfo(Variant::Type::BOOL, "succeeded"), PropertyInfo(Variant::Type::INT, "component"), PropertyInfo(Variant::Type::BOOL, "enabled")));
82+
}
83+
84+
String OpenXRFbSpatialEntity::_to_string() const {
85+
return String("[OpenXRFbSpatialEntity ") + uuid + String("]");
86+
}
87+
88+
StringName OpenXRFbSpatialEntity::get_uuid() const {
89+
return uuid;
90+
}
91+
92+
Array OpenXRFbSpatialEntity::get_supported_components() const {
93+
Array ret;
94+
95+
Vector<XrSpaceComponentTypeFB> components = OpenXRFbSpatialEntityExtensionWrapper::get_singleton()->get_support_components(space);
96+
ret.resize(components.size());
97+
for (int i = 0; i < components.size(); i++) {
98+
ret[i] = from_openxr_component_type(components[i]);
99+
}
100+
101+
return ret;
102+
}
103+
104+
bool OpenXRFbSpatialEntity::is_component_supported(ComponentType p_component) const {
105+
return get_supported_components().has(p_component);
106+
}
107+
108+
bool OpenXRFbSpatialEntity::is_component_enabled(ComponentType p_component) const {
109+
return OpenXRFbSpatialEntityExtensionWrapper::get_singleton()->is_component_enabled(space, to_openxr_component_type(p_component));
110+
}
111+
112+
void OpenXRFbSpatialEntity::set_component_enabled(ComponentType p_component, bool p_enabled) {
113+
Ref<OpenXRFbSpatialEntity> *userdata = memnew(Ref<OpenXRFbSpatialEntity>(this));
114+
XrAsyncRequestIdFB request_id = OpenXRFbSpatialEntityExtensionWrapper::get_singleton()->set_component_enabled(space, to_openxr_component_type(p_component), p_enabled, OpenXRFbSpatialEntity::_on_set_component_enabled_completed, userdata);
115+
}
116+
117+
void OpenXRFbSpatialEntity::_on_set_component_enabled_completed(XrResult p_result, XrSpaceComponentTypeFB p_component, bool p_enabled, void *p_userdata) {
118+
Ref<OpenXRFbSpatialEntity> *userdata = (Ref<OpenXRFbSpatialEntity> *)p_userdata;
119+
(*userdata)->emit_signal("openxr_fb_spatial_entity_set_component_enabled_completed", XR_SUCCEEDED(p_result), from_openxr_component_type(p_component), p_enabled);
120+
memdelete(userdata);
121+
}
122+
123+
PackedStringArray OpenXRFbSpatialEntity::get_semantic_labels() const {
124+
return OpenXRFbSceneExtensionWrapper::get_singleton()->get_semantic_labels(space);
125+
}
126+
127+
Dictionary OpenXRFbSpatialEntity::get_room_layout() const {
128+
OpenXRFbSceneExtensionWrapper::RoomLayout room_layout;
129+
if (!OpenXRFbSceneExtensionWrapper::get_singleton()->get_room_layout(space, room_layout)) {
130+
return Dictionary();
131+
}
132+
133+
Dictionary ret;
134+
ret["floor"] = OpenXRUtilities::uuid_to_string_name(room_layout.floor);
135+
ret["ceiling"] = OpenXRUtilities::uuid_to_string_name(room_layout.ceiling);
136+
137+
Array walls_array;
138+
walls_array.resize(room_layout.walls.size());
139+
for (int i = 0; i < room_layout.walls.size(); i++) {
140+
walls_array[i] = OpenXRUtilities::uuid_to_string_name(room_layout.walls[i]);
141+
}
142+
ret["walls"] = walls_array;
143+
144+
return ret;
145+
}
146+
147+
Array OpenXRFbSpatialEntity::get_contained_uuids() const {
148+
Vector<XrUuidEXT> uuids = OpenXRFbSpatialEntityContainerExtensionWrapper::get_singleton()->get_contained_uuids(space);
149+
150+
Array ret;
151+
ret.resize(uuids.size());
152+
for (int i = 0; i < uuids.size(); i++) {
153+
ret[i] = OpenXRUtilities::uuid_to_string_name(uuids[i]);
154+
}
155+
return ret;
156+
}
157+
158+
Rect2 OpenXRFbSpatialEntity::get_bounding_box_2d() const {
159+
return OpenXRFbSceneExtensionWrapper::get_singleton()->get_bounding_box_2d(space);
160+
}
161+
162+
AABB OpenXRFbSpatialEntity::get_bounding_box_3d() const {
163+
return OpenXRFbSceneExtensionWrapper::get_singleton()->get_bounding_box_3d(space);
164+
}
165+
166+
PackedVector2Array OpenXRFbSpatialEntity::get_boundary_2d() const {
167+
return OpenXRFbSceneExtensionWrapper::get_singleton()->get_boundary_2d(space);
168+
}
169+
170+
void OpenXRFbSpatialEntity::track() {
171+
ERR_FAIL_COND_MSG(!is_component_enabled(COMPONENT_TYPE_LOCATABLE), vformat("Cannot track spatial entity %s because COMPONENT_TYPE_LOCATABLE isn't enabled.", uuid));
172+
OpenXRFbSpatialEntityExtensionWrapper::get_singleton()->track_entity(uuid, space);
173+
}
174+
175+
void OpenXRFbSpatialEntity::untrack() {
176+
OpenXRFbSpatialEntityExtensionWrapper::get_singleton()->untrack_entity(uuid);
177+
}
178+
179+
bool OpenXRFbSpatialEntity::is_tracked() const {
180+
return OpenXRFbSpatialEntityExtensionWrapper::get_singleton()->is_entity_tracked(uuid);
181+
}
182+
183+
MeshInstance3D *OpenXRFbSpatialEntity::create_mesh_instance() const {
184+
MeshInstance3D *mesh_instance = nullptr;
185+
186+
if (is_component_enabled(COMPONENT_TYPE_BOUNDED_3D)) {
187+
Ref<BoxMesh> box_mesh;
188+
box_mesh.instantiate();
189+
190+
AABB bounding_box = get_bounding_box_3d();
191+
box_mesh->set_size(bounding_box.size);
192+
193+
mesh_instance = memnew(MeshInstance3D);
194+
mesh_instance->set_mesh(box_mesh);
195+
mesh_instance->set_position(bounding_box.get_center());
196+
197+
} else if (is_component_enabled(COMPONENT_TYPE_BOUNDED_2D)) {
198+
Ref<PlaneMesh> plane_mesh;
199+
plane_mesh.instantiate();
200+
201+
Rect2 bounding_box = get_bounding_box_2d();
202+
plane_mesh->set_size(bounding_box.size);
203+
204+
mesh_instance = memnew(MeshInstance3D);
205+
mesh_instance->set_mesh(plane_mesh);
206+
207+
Vector2 plane_center = bounding_box.get_center();
208+
mesh_instance->rotate_x(Math_PI / 2.0);
209+
mesh_instance->set_position(Vector3(plane_center.x, plane_center.y, 0));
210+
}
211+
212+
return mesh_instance;
213+
}
214+
215+
Node3D *OpenXRFbSpatialEntity::create_collision_shape() const {
216+
if (is_component_enabled(COMPONENT_TYPE_BOUNDED_3D)) {
217+
Ref<BoxShape3D> box_shape;
218+
box_shape.instantiate();
219+
220+
AABB bounding_box = get_bounding_box_3d();
221+
box_shape->set_size(bounding_box.size);
222+
223+
CollisionShape3D *collision_shape = memnew(CollisionShape3D);
224+
collision_shape->set_shape(box_shape);
225+
collision_shape->set_position(bounding_box.get_center());
226+
227+
return collision_shape;
228+
} else if (is_component_enabled(COMPONENT_TYPE_BOUNDED_2D)) {
229+
Ref<BoxShape3D> box_shape;
230+
box_shape.instantiate();
231+
232+
Rect2 bounding_box = get_bounding_box_2d();
233+
box_shape->set_size(Vector3(bounding_box.size.x, 0, bounding_box.size.y));
234+
235+
CollisionShape3D *collision_shape = memnew(CollisionShape3D);
236+
collision_shape->set_shape(box_shape);
237+
238+
Vector2 plane_center = bounding_box.get_center();
239+
collision_shape->rotate_x(Math_PI / 2.0);
240+
collision_shape->set_position(Vector3(plane_center.x, plane_center.y, 0));
241+
242+
return collision_shape;
243+
}
244+
245+
return nullptr;
246+
}
247+
248+
XrSpaceStorageLocationFB OpenXRFbSpatialEntity::to_openxr_storage_location(StorageLocation p_location) {
249+
switch (p_location) {
250+
case OpenXRFbSpatialEntity::STORAGE_LOCAL: {
251+
return XR_SPACE_STORAGE_LOCATION_LOCAL_FB;
252+
} break;
253+
case OpenXRFbSpatialEntity::STORAGE_CLOUD: {
254+
return XR_SPACE_STORAGE_LOCATION_CLOUD_FB;
255+
} break;
256+
default: {
257+
return XR_SPACE_STORAGE_LOCATION_INVALID_FB;
258+
}
259+
}
260+
}
261+
262+
XrSpaceComponentTypeFB OpenXRFbSpatialEntity::to_openxr_component_type(ComponentType p_component) {
263+
switch (p_component) {
264+
case COMPONENT_TYPE_LOCATABLE: {
265+
return XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB;
266+
} break;
267+
case COMPONENT_TYPE_STORABLE: {
268+
return XR_SPACE_COMPONENT_TYPE_STORABLE_FB;
269+
} break;
270+
case COMPONENT_TYPE_SHARABLE: {
271+
return XR_SPACE_COMPONENT_TYPE_SHARABLE_FB;
272+
} break;
273+
case COMPONENT_TYPE_BOUNDED_2D: {
274+
return XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB;
275+
} break;
276+
case COMPONENT_TYPE_BOUNDED_3D: {
277+
return XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB;
278+
} break;
279+
case COMPONENT_TYPE_SEMANTIC_LABELS: {
280+
return XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB;
281+
} break;
282+
case COMPONENT_TYPE_ROOM_LAYOUT: {
283+
return XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB;
284+
} break;
285+
case COMPONENT_TYPE_CONTAINER: {
286+
return XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB;
287+
} break;
288+
case COMPONENT_TYPE_TRIANGLE_MESH: {
289+
return XR_SPACE_COMPONENT_TYPE_TRIANGLE_MESH_META;
290+
} break;
291+
default: {
292+
ERR_FAIL_V_MSG(XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB, vformat("Unknown component type: %s", p_component));
293+
}
294+
}
295+
}
296+
297+
OpenXRFbSpatialEntity::ComponentType OpenXRFbSpatialEntity::from_openxr_component_type(XrSpaceComponentTypeFB p_component) {
298+
switch (p_component) {
299+
case XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB: {
300+
return COMPONENT_TYPE_LOCATABLE;
301+
} break;
302+
case XR_SPACE_COMPONENT_TYPE_STORABLE_FB: {
303+
return COMPONENT_TYPE_STORABLE;
304+
} break;
305+
case XR_SPACE_COMPONENT_TYPE_SHARABLE_FB: {
306+
return COMPONENT_TYPE_SHARABLE;
307+
} break;
308+
case XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB: {
309+
return COMPONENT_TYPE_BOUNDED_2D;
310+
} break;
311+
case XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB: {
312+
return COMPONENT_TYPE_BOUNDED_3D;
313+
} break;
314+
case XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB: {
315+
return COMPONENT_TYPE_SEMANTIC_LABELS;
316+
} break;
317+
case XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB: {
318+
return COMPONENT_TYPE_ROOM_LAYOUT;
319+
} break;
320+
case XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB: {
321+
return COMPONENT_TYPE_CONTAINER;
322+
} break;
323+
case XR_SPACE_COMPONENT_TYPE_TRIANGLE_MESH_META: {
324+
return COMPONENT_TYPE_TRIANGLE_MESH;
325+
} break;
326+
case XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB:
327+
default: {
328+
ERR_FAIL_V_MSG(COMPONENT_TYPE_LOCATABLE, vformat("Unknown OpenXR component type: %s", p_component));
329+
}
330+
}
331+
}
332+
333+
XrSpace OpenXRFbSpatialEntity::get_space() {
334+
return space;
335+
}
336+
337+
OpenXRFbSpatialEntity::OpenXRFbSpatialEntity(XrSpace p_space, const XrUuidEXT &p_uuid) {
338+
space = p_space;
339+
uuid = OpenXRUtilities::uuid_to_string_name(p_uuid);
340+
}

0 commit comments

Comments
 (0)