OpenXR: Implement spatial entities extension
This commit is contained in:
@ -7,6 +7,7 @@ Import("env_openxr")
|
||||
module_obj = []
|
||||
|
||||
env_openxr.add_source_files(module_obj, "*.cpp")
|
||||
env_openxr.add_source_files(module_obj, "spatial_entities/*.cpp")
|
||||
|
||||
# These are platform dependent
|
||||
if env["platform"] == "android":
|
||||
|
||||
@ -73,7 +73,7 @@ public:
|
||||
// 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`.
|
||||
// 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_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.
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#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.
|
||||
|
||||
Asynchronous functions will return a future object which can be
|
||||
|
||||
1184
modules/openxr/extensions/spatial_entities/openxr_spatial_anchor.cpp
Normal file
1184
modules/openxr/extensions/spatial_entities/openxr_spatial_anchor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
@ -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)
|
||||
}
|
||||
@ -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
@ -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);
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user