Skip to content

Commit

Permalink
Add OpenXR fb_render_model extension wrapper and OpenXRFBRenderModel …
Browse files Browse the repository at this point in the history
…node
  • Loading branch information
devloglogan committed Feb 26, 2024
1 parent c63b6d1 commit c4b058d
Show file tree
Hide file tree
Showing 12 changed files with 583 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Upgrade Android, Gradle, Godot and Kotlin dependencies
- Add XR_FB_face_tracking support
- Update to OpenXR 1.0.34 headers
- Add XR_FB_render_model extension wrapper and OpenXRFBRenderModel node

## 2.0.3
- Migrate the export scripts from gdscript to C++ via gdextension
Expand Down
1 change: 1 addition & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ sources = []
sources += Glob("#common/src/main/cpp/*.cpp")
sources += Glob("#common/src/main/cpp/export/*.cpp")
sources += Glob("#common/src/main/cpp/extensions/*.cpp")
sources += Glob("#common/src/main/cpp/classes/*.cpp")

binary_path = '#demo/addons/godotopenxrvendors/.bin'
project_name = 'godotopenxrvendors'
Expand Down
138 changes: 138 additions & 0 deletions common/src/main/cpp/classes/openxr_fb_render_model.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**************************************************************************/
/* openxr_fb_render_model.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT XR */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2022-present Godot XR contributors (see CONTRIBUTORS.md) */
/* */
/* 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 "classes/openxr_fb_render_model.h"

#include "extensions/openxr_fb_render_model_extension_wrapper.h"

#include <godot_cpp/classes/gltf_document.hpp>
#include <godot_cpp/classes/gltf_state.hpp>
#include <godot_cpp/classes/open_xr_interface.hpp>
#include <godot_cpp/classes/xr_server.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

using namespace godot;

void OpenXRFbRenderModel::set_render_model_type(Model p_model) {
render_model_type = p_model;
if (is_inside_tree() && OpenXRFbRenderModelExtensionWrapper::get_singleton()->is_openxr_session_active()) {
load_render_model();
}
}

OpenXRFbRenderModel::Model OpenXRFbRenderModel::get_render_model_type() {
return render_model_type;
}

bool OpenXRFbRenderModel::has_render_model_node() {
return render_model_node != nullptr;
}

void OpenXRFbRenderModel::load_render_model() {
if (render_model_node != nullptr) {
render_model_node->queue_free();
render_model_node = nullptr;
}

String render_model_path;
switch (render_model_type) {
case MODEL_CONTROLLER_LEFT: {
render_model_path = "/model_fb/controller/left";
} break;

case MODEL_CONTROLLER_RIGHT: {
render_model_path = "/model_fb/controller/right";
} break;

default: {
render_model_path = "";
}
}

if (render_model_path.is_empty()) {
return;
}

PackedByteArray render_model_buffer = OpenXRFbRenderModelExtensionWrapper::get_singleton()->get_buffer(render_model_path);
if (render_model_buffer.is_empty()) {
UtilityFunctions::print_verbose("Failed to load render model buffer from path [", render_model_path, "] in OpenXRFbRenderModel node");
return;
}

Ref<GLTFDocument> gltf_document;
gltf_document.instantiate();
Ref<GLTFState> gltf_state;
gltf_state.instantiate();

Error err = gltf_document->append_from_buffer(render_model_buffer, "", gltf_state);
if (err != OK) {
UtilityFunctions::print_verbose("Failed to instance render model in OpenXRFbRenderModel node");
return;
}

render_model_node = Object::cast_to<Node3D>(gltf_document->generate_scene(gltf_state));
if (render_model_node) {
add_child(render_model_node);
emit_signal("openxr_fb_render_model_loaded");
}
}

Node3D *OpenXRFbRenderModel::get_render_model_node() {
return render_model_node;
}

void OpenXRFbRenderModel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POSTINITIALIZE: {
Ref<OpenXRInterface> openxr_interface = XRServer::get_singleton()->find_interface("OpenXR");
if (openxr_interface.is_valid()) {
openxr_interface->connect("session_begun", callable_mp(this, &OpenXRFbRenderModel::load_render_model));
}
} break;
case NOTIFICATION_ENTER_TREE: {
if (OpenXRFbRenderModelExtensionWrapper::get_singleton()->is_openxr_session_active()) {
load_render_model();
}
} break;
}
}

void OpenXRFbRenderModel::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_render_model_node"), &OpenXRFbRenderModel::has_render_model_node);
ClassDB::bind_method(D_METHOD("get_render_model_node"), &OpenXRFbRenderModel::get_render_model_node);
ClassDB::bind_method(D_METHOD("set_render_model_type", "render_model_type"), &OpenXRFbRenderModel::set_render_model_type);
ClassDB::bind_method(D_METHOD("get_render_model_type"), &OpenXRFbRenderModel::get_render_model_type);

ADD_PROPERTY(PropertyInfo(Variant::INT, "render_model_type", PROPERTY_HINT_ENUM, "Left Controller,Right Controller"), "set_render_model_type", "get_render_model_type");

BIND_ENUM_CONSTANT(MODEL_CONTROLLER_LEFT);
BIND_ENUM_CONSTANT(MODEL_CONTROLLER_RIGHT);

ADD_SIGNAL(MethodInfo("openxr_fb_render_model_loaded"));
}
26 changes: 26 additions & 0 deletions common/src/main/cpp/export/meta_export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ MetaEditorExportPlugin::MetaEditorExportPlugin() {
PROPERTY_USAGE_DEFAULT,
PASSTHROUGH_NONE_VALUE,
false);
_render_model_option = _generate_export_option(
"meta_xr_features/render_model",
"",
Variant::Type::INT,
PROPERTY_HINT_ENUM,
"None,Optional,Required",
PROPERTY_USAGE_DEFAULT,
RENDER_MODEL_NONE_VALUE,
false);
_use_anchor_api_option = _generate_export_option(
"meta_xr_features/use_anchor_api",
"",
Expand Down Expand Up @@ -193,6 +202,7 @@ TypedArray<Dictionary> MetaEditorExportPlugin::_get_export_options(const Ref<Edi
export_options.append(_hand_tracking_option);
export_options.append(_hand_tracking_frequency_option);
export_options.append(_passthrough_option);
export_options.append(_render_model_option);
export_options.append(_use_anchor_api_option);
export_options.append(_use_scene_api_option);
export_options.append(_use_overlay_keyboard_option);
Expand Down Expand Up @@ -276,6 +286,10 @@ String MetaEditorExportPlugin::_get_export_option_warning(const Ref<EditorExport
if (!openxr_enabled && _get_int_option(option, PASSTHROUGH_NONE_VALUE) > PASSTHROUGH_NONE_VALUE) {
return "\"Passthrough\" requires \"XR Mode\" to be \"OpenXR\".\n";
}
} else if (option == "meta_xr_features/render_model") {
if (!openxr_enabled && _get_int_option(option, RENDER_MODEL_NONE_VALUE) > RENDER_MODEL_NONE_VALUE) {
return "\"Render Model\" requires \"XR Mode\" to be \"OpenXR\".\n";
}
} else if (option == "meta_xr_features/use_anchor_api") {
if (!openxr_enabled && _get_bool_option(option)) {
return "\"Use anchor API\" is only valid when \"XR Mode\" is \"OpenXR\".\n";
Expand Down Expand Up @@ -347,6 +361,18 @@ String MetaEditorExportPlugin::_get_android_manifest_element_contents(const Ref<
contents += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"true\" />\n";
}

// Check for render model
int render_model_value = _get_int_option("meta_xr_features/render_model", RENDER_MODEL_NONE_VALUE);
if (render_model_value > RENDER_MODEL_NONE_VALUE) {
contents += " <uses-permission android:name=\"com.oculus.permission.RENDER_MODEL\" />\n";

if (render_model_value == RENDER_MODEL_OPTIONAL_VALUE) {
contents += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.RENDER_MODEL\" android:required=\"false\" />\n";
} else if (render_model_value == RENDER_MODEL_REQUIRED_VALUE) {
contents += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.RENDER_MODEL\" android:required=\"true\" />\n";
}
}

// Check for anchor api
bool use_anchor_api = _get_bool_option("meta_xr_features/use_anchor_api");
if (use_anchor_api) {
Expand Down
Loading

0 comments on commit c4b058d

Please sign in to comment.