123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795 |
- /**************************************************************************/
- /* openxr_render_model_extension.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_render_model_extension.h"
- #include "../openxr_api.h"
- #include "../openxr_interface.h"
- #include "core/config/project_settings.h"
- #include "core/string/print_string.h"
- #include "servers/xr_server.h"
- OpenXRRenderModelExtension *OpenXRRenderModelExtension::singleton = nullptr;
- OpenXRRenderModelExtension *OpenXRRenderModelExtension::get_singleton() {
- return singleton;
- }
- void OpenXRRenderModelExtension::_bind_methods() {
- ClassDB::bind_method(D_METHOD("is_active"), &OpenXRRenderModelExtension::is_active);
- ClassDB::bind_method(D_METHOD("render_model_create", "render_model_id"), &OpenXRRenderModelExtension::render_model_create);
- ClassDB::bind_method(D_METHOD("render_model_destroy", "render_model"), &OpenXRRenderModelExtension::render_model_destroy);
- ClassDB::bind_method(D_METHOD("render_model_get_all"), &OpenXRRenderModelExtension::render_model_get_all);
- ClassDB::bind_method(D_METHOD("render_model_new_scene_instance", "render_model"), &OpenXRRenderModelExtension::render_model_new_scene_instance);
- ClassDB::bind_method(D_METHOD("render_model_get_subaction_paths", "render_model"), &OpenXRRenderModelExtension::render_model_get_subaction_paths);
- ClassDB::bind_method(D_METHOD("render_model_get_top_level_path", "render_model"), &OpenXRRenderModelExtension::render_model_get_top_level_path_as_string);
- ClassDB::bind_method(D_METHOD("render_model_get_confidence", "render_model"), &OpenXRRenderModelExtension::render_model_get_confidence);
- ClassDB::bind_method(D_METHOD("render_model_get_root_transform", "render_model"), &OpenXRRenderModelExtension::render_model_get_root_transform);
- ClassDB::bind_method(D_METHOD("render_model_get_animatable_node_count", "render_model"), &OpenXRRenderModelExtension::render_model_get_animatable_node_count);
- ClassDB::bind_method(D_METHOD("render_model_get_animatable_node_name", "render_model", "index"), &OpenXRRenderModelExtension::render_model_get_animatable_node_name);
- ClassDB::bind_method(D_METHOD("render_model_is_animatable_node_visible", "render_model", "index"), &OpenXRRenderModelExtension::render_model_is_animatable_node_visible);
- ClassDB::bind_method(D_METHOD("render_model_get_animatable_node_transform", "render_model", "index"), &OpenXRRenderModelExtension::render_model_get_animatable_node_transform);
- ADD_SIGNAL(MethodInfo("render_model_added", PropertyInfo(Variant::RID, "render_model")));
- ADD_SIGNAL(MethodInfo("render_model_removed", PropertyInfo(Variant::RID, "render_model")));
- ADD_SIGNAL(MethodInfo("render_model_top_level_path_changed", PropertyInfo(Variant::RID, "render_model")));
- }
- OpenXRRenderModelExtension::OpenXRRenderModelExtension() {
- singleton = this;
- }
- OpenXRRenderModelExtension::~OpenXRRenderModelExtension() {
- singleton = nullptr;
- }
- HashMap<String, bool *> OpenXRRenderModelExtension::get_requested_extensions() {
- HashMap<String, bool *> request_extensions;
- if (GLOBAL_GET("xr/openxr/extensions/render_model")) {
- request_extensions[XR_EXT_UUID_EXTENSION_NAME] = &uuid_ext;
- request_extensions[XR_EXT_RENDER_MODEL_EXTENSION_NAME] = &render_model_ext;
- request_extensions[XR_EXT_INTERACTION_RENDER_MODEL_EXTENSION_NAME] = &interaction_render_model_ext;
- }
- return request_extensions;
- }
- void OpenXRRenderModelExtension::on_instance_created(const XrInstance p_instance) {
- // Standard entry points we use.
- EXT_INIT_XR_FUNC(xrLocateSpace);
- EXT_INIT_XR_FUNC(xrDestroySpace);
- EXT_INIT_XR_FUNC(xrPathToString);
- if (render_model_ext) {
- EXT_INIT_XR_FUNC(xrCreateRenderModelEXT);
- EXT_INIT_XR_FUNC(xrDestroyRenderModelEXT);
- EXT_INIT_XR_FUNC(xrGetRenderModelPropertiesEXT);
- EXT_INIT_XR_FUNC(xrCreateRenderModelSpaceEXT);
- EXT_INIT_XR_FUNC(xrCreateRenderModelAssetEXT);
- EXT_INIT_XR_FUNC(xrDestroyRenderModelAssetEXT);
- EXT_INIT_XR_FUNC(xrGetRenderModelAssetDataEXT);
- EXT_INIT_XR_FUNC(xrGetRenderModelAssetPropertiesEXT);
- EXT_INIT_XR_FUNC(xrGetRenderModelStateEXT);
- }
- if (interaction_render_model_ext) {
- EXT_INIT_XR_FUNC(xrEnumerateInteractionRenderModelIdsEXT);
- EXT_INIT_XR_FUNC(xrEnumerateRenderModelSubactionPathsEXT);
- EXT_INIT_XR_FUNC(xrGetRenderModelPoseTopLevelUserPathEXT);
- }
- }
- void OpenXRRenderModelExtension::on_session_created(const XrSession p_session) {
- _interaction_data_dirty = true;
- }
- void OpenXRRenderModelExtension::on_instance_destroyed() {
- xrCreateRenderModelEXT_ptr = nullptr;
- xrDestroyRenderModelEXT_ptr = nullptr;
- xrGetRenderModelPropertiesEXT_ptr = nullptr;
- xrCreateRenderModelSpaceEXT_ptr = nullptr;
- xrCreateRenderModelAssetEXT_ptr = nullptr;
- xrDestroyRenderModelAssetEXT_ptr = nullptr;
- xrGetRenderModelAssetDataEXT_ptr = nullptr;
- xrGetRenderModelAssetPropertiesEXT_ptr = nullptr;
- xrGetRenderModelStateEXT_ptr = nullptr;
- xrEnumerateInteractionRenderModelIdsEXT_ptr = nullptr;
- xrEnumerateRenderModelSubactionPathsEXT_ptr = nullptr;
- xrGetRenderModelPoseTopLevelUserPathEXT_ptr = nullptr;
- uuid_ext = false;
- render_model_ext = false;
- interaction_render_model_ext = false;
- }
- void OpenXRRenderModelExtension::on_session_destroyed() {
- _clear_interaction_data();
- _clear_render_model_data();
- // We no longer have valid sync data.
- xr_sync_has_run = false;
- }
- bool OpenXRRenderModelExtension::on_event_polled(const XrEventDataBuffer &event) {
- if (event.type == XR_TYPE_EVENT_DATA_INTERACTION_RENDER_MODELS_CHANGED_EXT) {
- // Mark interaction data as dirty so that we update it on sync.
- _interaction_data_dirty = true;
- return true;
- } else if (event.type == XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) {
- // If our controller bindings changed, its likely our render models change too.
- // We should be getting a XR_TYPE_EVENT_DATA_INTERACTION_RENDER_MODELS_CHANGED_EXT
- // but checking for this scenario just in case.
- _interaction_data_dirty = true;
- // Do not consider this handled, we simply do additional logic.
- return false;
- }
- return false;
- }
- void OpenXRRenderModelExtension::on_sync_actions() {
- if (!is_active()) {
- return;
- }
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL(openxr_api);
- // Mark sync as run
- xr_sync_has_run = true;
- // Update our interaction data if needed
- if (_interaction_data_dirty) {
- _update_interaction_data();
- }
- // Loop through all of our render models to update our space and state info
- LocalVector<RID> owned = render_model_owner.get_owned_list();
- for (const RID &rid : owned) {
- RenderModel *render_model = render_model_owner.get_or_null(rid);
- if (render_model && render_model->xr_space != XR_NULL_HANDLE) {
- XrSpaceLocation render_model_location = {
- XR_TYPE_SPACE_LOCATION, // type
- nullptr, // next
- 0, // locationFlags
- { { 0.0, 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 } }, // pose
- };
- XrResult result = xrLocateSpace(render_model->xr_space, openxr_api->get_play_space(), openxr_api->get_predicted_display_time(), &render_model_location);
- ERR_CONTINUE_MSG(XR_FAILED(result), "OpenXR: Failed to locate render model space [" + openxr_api->get_error_string(result) + "]");
- render_model->confidence = openxr_api->transform_from_location(render_model_location, render_model->root_transform);
- if (!render_model->node_states.is_empty()) {
- // Get node states.
- XrRenderModelStateGetInfoEXT get_state_info = {
- XR_TYPE_RENDER_MODEL_STATE_GET_INFO_EXT, // type
- nullptr, // next
- openxr_api->get_predicted_display_time() // displayTime
- };
- XrRenderModelStateEXT state = {
- XR_TYPE_RENDER_MODEL_STATE_EXT, // type
- nullptr, // next
- render_model->animatable_node_count, // nodeStateCount
- render_model->node_states.ptr(), // nodeStates
- };
- result = xrGetRenderModelStateEXT(render_model->xr_render_model, &get_state_info, &state);
- if (XR_FAILED(result)) {
- ERR_PRINT("OpenXR: Failed to update node states [" + openxr_api->get_error_string(result) + "]");
- }
- }
- XrPath new_path = XR_NULL_PATH;
- if (toplevel_paths.is_empty()) {
- // Set this up just once with paths we support here.
- toplevel_paths.push_back(openxr_api->get_xr_path("/user/hand/left"));
- toplevel_paths.push_back(openxr_api->get_xr_path("/user/hand/right"));
- }
- XrInteractionRenderModelTopLevelUserPathGetInfoEXT info = {
- XR_TYPE_INTERACTION_RENDER_MODEL_TOP_LEVEL_USER_PATH_GET_INFO_EXT, // type
- nullptr, // next
- (uint32_t)toplevel_paths.size(), // topLevelUserPathCount
- toplevel_paths.ptr() // topLevelUserPaths
- };
- result = xrGetRenderModelPoseTopLevelUserPathEXT(render_model->xr_render_model, &info, &new_path);
- if (XR_FAILED(result)) {
- ERR_PRINT("OpenXR: Failed to update the top level path for render models [" + openxr_api->get_error_string(result) + "]");
- } else if (new_path != render_model->top_level_path) {
- print_verbose("OpenXR: Render model top level path changed to " + openxr_api->get_xr_path_name(new_path));
- // Set the new path
- render_model->top_level_path = new_path;
- // And broadcast it
- // Note, converting an XrPath to a String has overhead, so we won't do this automatically.
- emit_signal(SNAME("render_model_top_level_path_changed"), rid);
- }
- }
- }
- }
- bool OpenXRRenderModelExtension::is_active() const {
- return render_model_ext && interaction_render_model_ext;
- }
- void OpenXRRenderModelExtension::_clear_interaction_data() {
- for (const KeyValue<XrRenderModelIdEXT, RID> &e : interaction_render_models) {
- render_model_destroy(e.value);
- }
- interaction_render_models.clear();
- }
- bool OpenXRRenderModelExtension::_update_interaction_data() {
- ERR_FAIL_COND_V_MSG(!interaction_render_model_ext, false, "Interaction render model extension hasn't been enabled.");
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL_V(openxr_api, false);
- XrSession session = openxr_api->get_session();
- ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
- // Check if syncActions has been run at least once or there is no point in getting data.
- if (!xr_sync_has_run) {
- // Do not treat this as an error.
- return true;
- }
- // If we get this far, no longer mark as dirty.
- // Else we just repeat the same error over and over again.
- _interaction_data_dirty = false;
- // Obtain interaction info.
- XrInteractionRenderModelIdsEnumerateInfoEXT interaction_info = {
- XR_TYPE_INTERACTION_RENDER_MODEL_IDS_ENUMERATE_INFO_EXT, // type
- nullptr, // next
- };
- // Obtain count.
- uint32_t interaction_count = 0;
- XrResult result = xrEnumerateInteractionRenderModelIdsEXT(session, &interaction_info, 0, &interaction_count, nullptr);
- if (XR_FAILED(result)) {
- // not successful? then we do nothing.
- ERR_FAIL_V_MSG(false, "OpenXR: Failed to obtain render model interaction id count [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- // Create some storage
- LocalVector<XrRenderModelIdEXT> render_model_interaction_ids;
- render_model_interaction_ids.resize(interaction_count);
- // Only need to fetch data if there is something to fetch (/we've got storage).
- if (!render_model_interaction_ids.is_empty()) {
- // Obtain interaction ids
- result = xrEnumerateInteractionRenderModelIdsEXT(session, &interaction_info, render_model_interaction_ids.size(), &interaction_count, render_model_interaction_ids.ptr());
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(false, "OpenXR: Failed to obtain render model interaction ids [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- }
- // Remove render models that are no longer tracked
- LocalVector<XrRenderModelIdEXT> erase_ids;
- for (const KeyValue<XrRenderModelIdEXT, RID> &e : interaction_render_models) {
- if (!render_model_interaction_ids.has(e.key)) {
- if (e.value.is_valid()) {
- render_model_destroy(e.value);
- }
- erase_ids.push_back(e.key);
- }
- }
- // Remove these from our hashmap
- for (const XrRenderModelIdEXT &id : erase_ids) {
- interaction_render_models.erase(id);
- }
- // Now update our models
- for (const XrRenderModelIdEXT &id : render_model_interaction_ids) {
- if (!interaction_render_models.has(id)) {
- // Even if this fails we add it so we don't repeat trying to create it
- interaction_render_models[id] = render_model_create(id);
- }
- }
- return true;
- }
- bool OpenXRRenderModelExtension::has_render_model(RID p_render_model) const {
- return render_model_owner.owns(p_render_model);
- }
- RID OpenXRRenderModelExtension::render_model_create(XrRenderModelIdEXT p_render_model_id) {
- ERR_FAIL_COND_V_MSG(!render_model_ext, RID(), "Render model extension hasn't been enabled.");
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL_V(openxr_api, RID());
- XrSession session = openxr_api->get_session();
- ERR_FAIL_COND_V(session == XR_NULL_HANDLE, RID());
- RenderModel render_model;
- render_model.xr_render_model_id = p_render_model_id;
- // Start with the extensions that are supported in our base (see GLTFDocument::_parse_gltf_extensions).
- Vector<const char *> supported_gltf_extensions = {
- "KHR_lights_punctual",
- "KHR_materials_pbrSpecularGlossiness",
- "KHR_texture_transform",
- "KHR_materials_unlit",
- "KHR_materials_emissive_strength",
- };
- // Now find anything we support through plugins, which is a bit of a pain as they are converted to Strings
- // and we need to convert them back.
- Vector<CharString> char_extensions; // Just for temp storage of our c-strings.
- Vector<Ref<GLTFDocumentExtension>> gltf_document_extensions = GLTFDocument::get_all_gltf_document_extensions();
- for (Ref<GLTFDocumentExtension> &gltf_document_extension : gltf_document_extensions) {
- Vector<String> supported_extensions = gltf_document_extension->get_supported_extensions();
- for (const String &extension : supported_extensions) {
- char_extensions.push_back(extension.utf8());
- }
- }
- // Now we can add them to our supported extensions list.
- for (const CharString &cs : char_extensions) {
- supported_gltf_extensions.push_back(cs.get_data());
- }
- XrRenderModelCreateInfoEXT create_info = {
- XR_TYPE_RENDER_MODEL_CREATE_INFO_EXT, // type
- nullptr, // next
- p_render_model_id, // renderModelId
- uint32_t(supported_gltf_extensions.size()), // gltfExtensionCount
- supported_gltf_extensions.ptr(), // gltfExtensions
- };
- XrResult result = xrCreateRenderModelEXT(session, &create_info, &render_model.xr_render_model);
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(RID(), "OpenXR: Failed to create render model [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- XrRenderModelPropertiesGetInfoEXT properties_info = {
- XR_TYPE_RENDER_MODEL_PROPERTIES_GET_INFO_EXT, // type
- nullptr, // next
- };
- XrRenderModelPropertiesEXT properties;
- result = xrGetRenderModelPropertiesEXT(render_model.xr_render_model, &properties_info, &properties);
- if (XR_FAILED(result)) {
- ERR_PRINT("OpenXR: Failed to get render model properties [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- } else {
- render_model.animatable_node_count = properties.animatableNodeCount;
- render_model.render_model_data = _get_render_model_data(properties.cacheId, properties.animatableNodeCount);
- }
- // Create space for positioning our asset.
- XrRenderModelSpaceCreateInfoEXT space_create_info = {
- XR_TYPE_RENDER_MODEL_SPACE_CREATE_INFO_EXT, // type
- nullptr, // next
- render_model.xr_render_model // renderModel
- };
- result = xrCreateRenderModelSpaceEXT(session, &space_create_info, &render_model.xr_space);
- if (XR_FAILED(result)) {
- ERR_PRINT("OpenXR: Failed to create render model space [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- if (render_model.animatable_node_count > 0) {
- render_model.node_states.resize(render_model.animatable_node_count);
- }
- RID new_rid = render_model_owner.make_rid(render_model);
- emit_signal(SNAME("render_model_added"), new_rid);
- return new_rid;
- }
- RID OpenXRRenderModelExtension::_render_model_create(uint64_t p_render_model_id) {
- RID ret;
- ERR_FAIL_COND_V(p_render_model_id == XR_NULL_RENDER_MODEL_ID_EXT, ret);
- if (is_active()) {
- ret = render_model_create(XrRenderModelIdEXT(p_render_model_id));
- }
- return ret;
- }
- void OpenXRRenderModelExtension::render_model_destroy(RID p_render_model) {
- ERR_FAIL_COND_MSG(!render_model_ext, "Render model extension hasn't been enabled.");
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL(render_model);
- emit_signal(SNAME("render_model_removed"), p_render_model);
- // Clean up.
- if (render_model->xr_space != XR_NULL_HANDLE) {
- xrDestroySpace(render_model->xr_space);
- }
- render_model->node_states.clear();
- // And destroy our model.
- XrResult result = xrDestroyRenderModelEXT(render_model->xr_render_model);
- if (XR_FAILED(result)) {
- ERR_PRINT("OpenXR: Failed to destroy render model [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- render_model_owner.free(p_render_model);
- }
- TypedArray<RID> OpenXRRenderModelExtension::render_model_get_all() {
- TypedArray<RID> ret;
- LocalVector<RID> rids = render_model_owner.get_owned_list();
- for (const RID &rid : rids) {
- ret.push_back(rid);
- }
- return ret;
- }
- Node3D *OpenXRRenderModelExtension::render_model_new_scene_instance(RID p_render_model) const {
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, nullptr);
- if (render_model->render_model_data.is_null()) {
- // We never loaded it (don't spam errors here).
- return nullptr;
- }
- return render_model->render_model_data->new_scene_instance();
- }
- PackedStringArray OpenXRRenderModelExtension::render_model_get_subaction_paths(RID p_render_model) {
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL_V(openxr_api, PackedStringArray());
- XrInstance instance = openxr_api->get_instance();
- ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, PackedStringArray());
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, PackedStringArray());
- PackedStringArray subaction_paths;
- XrInteractionRenderModelSubactionPathInfoEXT subaction_info = {
- XR_TYPE_INTERACTION_RENDER_MODEL_SUBACTION_PATH_INFO_EXT, // type
- nullptr, // next
- };
- uint32_t capacity;
- XrResult result = xrEnumerateRenderModelSubactionPathsEXT(render_model->xr_render_model, &subaction_info, 0, &capacity, nullptr);
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(PackedStringArray(), "OpenXR: Failed to obtain render model subaction path count [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- if (capacity > 0) {
- LocalVector<XrPath> paths;
- paths.resize(capacity);
- result = xrEnumerateRenderModelSubactionPathsEXT(render_model->xr_render_model, &subaction_info, capacity, &capacity, paths.ptr());
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(PackedStringArray(), "OpenXR: Failed to obtain render model subaction paths [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- for (uint32_t i = 0; i < capacity; i++) {
- char buffer[1024];
- uint32_t size = 0;
- xrPathToString(instance, paths[i], 1024, &size, buffer);
- if (size > 0) {
- subaction_paths.push_back(String(buffer));
- }
- }
- }
- return subaction_paths;
- }
- XrPath OpenXRRenderModelExtension::render_model_get_top_level_path(RID p_render_model) const {
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, XRPose::TrackingConfidence::XR_TRACKING_CONFIDENCE_NONE);
- return render_model->top_level_path;
- }
- String OpenXRRenderModelExtension::render_model_get_top_level_path_as_string(RID p_render_model) const {
- String ret;
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL_V(openxr_api, ret);
- if (is_active() && has_render_model(p_render_model)) {
- XrPath path = render_model_get_top_level_path(p_render_model);
- if (path == XR_NULL_PATH) {
- return "None";
- } else {
- return openxr_api->get_xr_path_name(path);
- }
- }
- return ret;
- }
- XRPose::TrackingConfidence OpenXRRenderModelExtension::render_model_get_confidence(RID p_render_model) const {
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, XRPose::TrackingConfidence::XR_TRACKING_CONFIDENCE_NONE);
- return render_model->confidence;
- }
- Transform3D OpenXRRenderModelExtension::render_model_get_root_transform(RID p_render_model) const {
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, Transform3D());
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, Transform3D());
- // Scale our root transform
- real_t world_scale = xr_server->get_world_scale();
- Transform3D root_transform = render_model->root_transform.scaled(Vector3(world_scale, world_scale, world_scale));
- return xr_server->get_reference_frame() * root_transform;
- }
- uint32_t OpenXRRenderModelExtension::render_model_get_animatable_node_count(RID p_render_model) const {
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, 0);
- return render_model->animatable_node_count;
- }
- String OpenXRRenderModelExtension::render_model_get_animatable_node_name(RID p_render_model, uint32_t p_index) const {
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, String());
- if (render_model->render_model_data.is_null()) {
- // We never loaded it (don't spam errors here).
- return String();
- }
- return render_model->render_model_data->get_node_name(p_index);
- }
- bool OpenXRRenderModelExtension::render_model_is_animatable_node_visible(RID p_render_model, uint32_t p_index) const {
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, false);
- ERR_FAIL_UNSIGNED_INDEX_V(p_index, render_model->animatable_node_count, false);
- if (render_model->node_states.is_empty()) {
- // Never allocated (don't spam errors here).
- return false;
- }
- return render_model->node_states[p_index].isVisible;
- }
- Transform3D OpenXRRenderModelExtension::render_model_get_animatable_node_transform(RID p_render_model, uint32_t p_index) const {
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL_V(openxr_api, Transform3D());
- RenderModel *render_model = render_model_owner.get_or_null(p_render_model);
- ERR_FAIL_NULL_V(render_model, Transform3D());
- ERR_FAIL_UNSIGNED_INDEX_V(p_index, render_model->animatable_node_count, Transform3D());
- if (render_model->node_states.is_empty()) {
- // Never allocated (don't spam errors here).
- return Transform3D();
- }
- return openxr_api->transform_from_pose(render_model->node_states[p_index].nodePose);
- }
- Ref<OpenXRRenderModelData> OpenXRRenderModelExtension::_get_render_model_data(XrUuidEXT p_cache_id, uint32_t p_animatable_node_count) {
- if (render_model_data_cache.has(p_cache_id)) {
- return render_model_data_cache[p_cache_id];
- }
- // We don't have this cached, lets load it up
- OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
- ERR_FAIL_NULL_V(openxr_api, nullptr);
- XrSession session = openxr_api->get_session();
- ERR_FAIL_COND_V(session == XR_NULL_HANDLE, nullptr);
- XrRenderModelAssetEXT asset;
- XrRenderModelAssetCreateInfoEXT create_info = {
- XR_TYPE_RENDER_MODEL_ASSET_CREATE_INFO_EXT, // type
- nullptr, // next
- p_cache_id // cacheId
- };
- XrResult result = xrCreateRenderModelAssetEXT(session, &create_info, &asset);
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(nullptr, "OpenXR: Failed to create render model asset [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- Ref<OpenXRRenderModelData> render_model_data = _load_asset(asset, p_animatable_node_count);
- // We're done with this :)
- result = xrDestroyRenderModelAssetEXT(asset);
- if (XR_FAILED(result)) {
- ERR_PRINT("OpenXR: Failed to destroy render model asset [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- // And cache it
- render_model_data_cache[p_cache_id] = render_model_data;
- return render_model_data;
- }
- Ref<OpenXRRenderModelData> OpenXRRenderModelExtension::_load_asset(XrRenderModelAssetEXT p_asset, uint32_t p_animatable_node_count) {
- XrRenderModelAssetDataGetInfoEXT get_info = {
- XR_TYPE_RENDER_MODEL_ASSET_DATA_GET_INFO_EXT, // type
- nullptr, // next
- };
- XrRenderModelAssetDataEXT asset_data = {
- XR_TYPE_RENDER_MODEL_ASSET_DATA_EXT, // type
- nullptr, // next
- 0, // bufferCapacityInput;
- 0, // bufferCountOutput;
- nullptr // buffer;
- };
- // Obtain required size for the buffer.
- XrResult result = xrGetRenderModelAssetDataEXT(p_asset, &get_info, &asset_data);
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(nullptr, "OpenXR: Failed to get render model buffer size [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- ERR_FAIL_COND_V(asset_data.bufferCountOutput == 0, nullptr);
- // Allocate data
- PackedByteArray buffer;
- buffer.resize(asset_data.bufferCountOutput);
- asset_data.buffer = buffer.ptrw();
- asset_data.bufferCapacityInput = asset_data.bufferCountOutput;
- // Now get our actual data.
- result = xrGetRenderModelAssetDataEXT(p_asset, &get_info, &asset_data);
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(nullptr, "OpenXR: Failed to get render model buffer [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- // Get the names of any animatable nodes
- PackedStringArray node_names;
- if (p_animatable_node_count > 0) {
- Vector<XrRenderModelAssetNodePropertiesEXT> node_properties;
- node_properties.resize(p_animatable_node_count);
- XrRenderModelAssetPropertiesGetInfoEXT properties_info = {
- XR_TYPE_RENDER_MODEL_ASSET_PROPERTIES_GET_INFO_EXT, // type
- nullptr, // next
- };
- XrRenderModelAssetPropertiesEXT asset_properties = {
- XR_TYPE_RENDER_MODEL_ASSET_PROPERTIES_EXT, // type
- nullptr, // next
- uint32_t(node_properties.size()), // nodePropertyCount
- node_properties.ptrw(), // nodeProperties
- };
- result = xrGetRenderModelAssetPropertiesEXT(p_asset, &properties_info, &asset_properties);
- if (XR_FAILED(result)) {
- ERR_FAIL_V_MSG(nullptr, "OpenXR: Failed to get render model property info [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
- }
- node_names.resize(p_animatable_node_count);
- String *node_names_ptrw = node_names.ptrw();
- for (uint32_t i = 0; i < p_animatable_node_count; i++) {
- node_names_ptrw[i] = String(node_properties[i].uniqueName);
- }
- }
- Ref<OpenXRRenderModelData> render_model_data;
- render_model_data.instantiate();
- render_model_data->parse_gltf_document(buffer);
- render_model_data->set_node_names(node_names);
- return render_model_data;
- }
- void OpenXRRenderModelExtension::_clear_render_model_data() {
- // Clear our toplevel paths filter.
- toplevel_paths.clear();
- // Clear our render model cache.
- render_model_data_cache.clear();
- // Loop through all of our render models and destroy them.
- LocalVector<RID> owned = render_model_owner.get_owned_list();
- for (const RID &rid : owned) {
- render_model_destroy(rid);
- }
- }
- bool OpenXRRenderModelData::parse_gltf_document(const PackedByteArray &p_bytes) {
- // State holds our data, document parses GLTF
- Ref<GLTFState> new_state;
- new_state.instantiate();
- Ref<GLTFDocument> new_gltf_document;
- new_gltf_document.instantiate();
- Error err = new_gltf_document->append_from_buffer(p_bytes, "", new_state);
- if (err != OK) {
- ERR_FAIL_V_MSG(false, "OpenXR: Failed to parse GLTF data.");
- }
- gltf_document = new_gltf_document;
- gltf_state = new_state;
- return true;
- }
- Node3D *OpenXRRenderModelData::new_scene_instance() {
- ERR_FAIL_COND_V(gltf_document.is_null(), nullptr);
- ERR_FAIL_COND_V(gltf_state.is_null(), nullptr);
- return Object::cast_to<Node3D>(gltf_document->generate_scene(gltf_state));
- }
- void OpenXRRenderModelData::set_node_names(const PackedStringArray &p_node_names) {
- node_names = p_node_names;
- }
- PackedStringArray OpenXRRenderModelData::get_node_names() const {
- return node_names;
- }
- const String OpenXRRenderModelData::get_node_name(uint32_t p_node_index) const {
- ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, node_names.size(), String());
- return node_names[p_node_index];
- }
- OpenXRRenderModelData::OpenXRRenderModelData() {
- }
- OpenXRRenderModelData::~OpenXRRenderModelData() {
- }
|