summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gdscript.cpp23
-rw-r--r--modules/gdscript/gdscript.h3
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp773
-rw-r--r--modules/gdscript/gdscript_analyzer.h21
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp2
-rw-r--r--modules/gdscript/gdscript_cache.cpp39
-rw-r--r--modules/gdscript/gdscript_cache.h10
-rw-r--r--modules/gdscript/gdscript_compiler.cpp41
-rw-r--r--modules/gdscript/gdscript_compiler.h1
-rw-r--r--modules/gdscript/gdscript_editor.cpp18
-rw-r--r--modules/gdscript/gdscript_parser.cpp52
-rw-r--r--modules/gdscript/gdscript_parser.h82
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp5
-rw-r--r--modules/gdscript/gdscript_vm.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.out5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.out7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_a.notest.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_b.notest.gd0
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_base.notest.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_c.notest.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_extend.notest.gd23
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd50
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order.out15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd39
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd12
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd35
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.out11
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd17
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.gd14
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.out3
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.gd11
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.out8
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml9
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp8
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp3
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.cpp3
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp10
-rw-r--r--modules/gltf/extensions/gltf_document_extension.cpp6
-rw-r--r--modules/gltf/extensions/gltf_document_extension.h4
-rw-r--r--modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp4
-rw-r--r--modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h4
-rw-r--r--modules/gltf/extensions/gltf_light.cpp2
-rw-r--r--modules/gltf/extensions/gltf_light.h4
-rw-r--r--modules/gltf/extensions/gltf_spec_gloss.cpp2
-rw-r--r--modules/gltf/extensions/gltf_spec_gloss.h3
-rw-r--r--modules/gltf/gltf_defines.h3
-rw-r--r--modules/gltf/gltf_document.cpp2064
-rw-r--r--modules/gltf/gltf_document.h319
-rw-r--r--modules/gltf/gltf_state.cpp2
-rw-r--r--modules/gltf/gltf_state.h20
-rw-r--r--modules/gltf/register_types.cpp16
-rw-r--r--modules/gltf/structures/gltf_accessor.h3
-rw-r--r--modules/gltf/structures/gltf_animation.h2
-rw-r--r--modules/gltf/structures/gltf_camera.cpp2
-rw-r--r--modules/gltf/structures/gltf_camera.h5
-rw-r--r--modules/gltf/structures/gltf_mesh.h4
-rw-r--r--modules/gltf/structures/gltf_texture_sampler.h1
-rw-r--r--modules/gridmap/grid_map.cpp2
-rw-r--r--modules/mono/README.md6
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py18
-rw-r--r--modules/mono/csharp_script.cpp6
-rw-r--r--modules/mono/csharp_script.h4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs27
-rw-r--r--modules/mono/editor/bindings_generator.cpp7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Signal.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs)11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj2
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml2
-rw-r--r--modules/multiplayer/scene_rpc_interface.cpp2
-rw-r--r--modules/navigation/godot_navigation_server.cpp34
-rw-r--r--modules/navigation/godot_navigation_server.h7
-rw-r--r--modules/navigation/nav_base.h4
-rw-r--r--modules/openxr/action_map/openxr_action.cpp6
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp34
-rw-r--r--modules/openxr/action_map/openxr_action_map.h4
-rw-r--r--modules/openxr/action_map/openxr_action_set.cpp10
-rw-r--r--modules/openxr/action_map/openxr_defs.cpp671
-rw-r--r--modules/openxr/action_map/openxr_defs.h124
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.cpp24
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.h3
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp713
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile_meta_data.h118
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp87
-rw-r--r--modules/openxr/editor/openxr_action_editor.h9
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp198
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h15
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp128
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h11
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp89
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.h15
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp4
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.h2
-rw-r--r--modules/openxr/extensions/openxr_android_extension.cpp2
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h5
-rw-r--r--modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp35
-rw-r--r--modules/openxr/extensions/openxr_htc_vive_tracker_extension.h1
-rw-r--r--modules/openxr/extensions/openxr_palm_pose_extension.cpp13
-rw-r--r--modules/openxr/extensions/openxr_palm_pose_extension.h2
-rw-r--r--modules/openxr/openxr_api.cpp121
-rw-r--r--modules/openxr/openxr_api.h18
-rw-r--r--modules/openxr/openxr_interface.cpp6
-rw-r--r--modules/openxr/register_types.cpp22
-rw-r--r--modules/raycast/config.py12
-rw-r--r--modules/regex/regex.cpp3
-rw-r--r--modules/register_module_types.h10
-rw-r--r--modules/text_server_adv/SCsub3
-rw-r--r--modules/text_server_adv/register_types.cpp2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp11
-rw-r--r--modules/text_server_fb/register_types.cpp2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp5
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannel.xml4
-rw-r--r--modules/webrtc/webrtc_data_channel_extension.h4
152 files changed, 4077 insertions, 2761 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index c8195de640..91f31174dd 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -478,7 +478,7 @@ void GDScript::_clear_doc() {
void GDScript::_update_doc() {
_clear_doc();
- doc.script_path = "\"" + get_path().get_slice("://", 1) + "\"";
+ doc.script_path = vformat(R"("%s")", get_script_path().get_slice("://", 1));
if (!name.is_empty()) {
doc.name = name;
} else {
@@ -701,6 +701,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
Variant default_value;
if (member.variable->initializer && member.variable->initializer->is_constant) {
default_value = member.variable->initializer->reduced_value;
+ GDScriptCompiler::convert_to_initializer_type(default_value, member.variable);
}
member_default_values_cache[member.variable->identifier->name] = default_value;
} break;
@@ -801,9 +802,9 @@ void GDScript::update_exports() {
String GDScript::_get_debug_path() const {
if (is_built_in() && !get_name().is_empty()) {
- return get_name() + " (" + get_path() + ")";
+ return vformat("%s(%s)", get_name(), get_script_path());
} else {
- return get_path();
+ return get_script_path();
}
}
@@ -904,7 +905,7 @@ Error GDScript::reload(bool p_keep_state) {
for (const GDScriptWarning &warning : parser.get_warnings()) {
if (EngineDebugger::is_active()) {
Vector<ScriptLanguage::StackInfo> si;
- EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), false, ERR_HANDLER_WARNING, si);
+ EngineDebugger::get_script_debugger()->send_error("", get_script_path(), warning.start_line, warning.get_name(), warning.get_message(), false, ERR_HANDLER_WARNING, si);
}
}
#endif
@@ -1027,6 +1028,10 @@ void GDScript::set_path(const String &p_path, bool p_take_over) {
}
}
+String GDScript::get_script_path() const {
+ return path;
+}
+
Error GDScript::load_source_code(const String &p_path) {
if (p_path.is_empty() || ResourceLoader::get_resource_type(p_path.get_slice("::", 0)) == "PackedScene") {
return OK;
@@ -1347,13 +1352,11 @@ void GDScript::_get_dependencies(RBSet<GDScript *> &p_dependencies, const GDScri
GDScript::GDScript() :
script_list(this) {
-#ifdef DEBUG_ENABLED
{
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
GDScriptLanguage::get_singleton()->script_list.add(&script_list);
}
-#endif
}
void GDScript::_save_orphaned_subclasses() {
@@ -1487,13 +1490,11 @@ GDScript::~GDScript() {
}
}
-#ifdef DEBUG_ENABLED
{
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
GDScriptLanguage::get_singleton()->script_list.remove(&script_list);
}
-#endif
if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown.
GDScriptCache::remove_script(get_path());
@@ -2164,7 +2165,8 @@ void GDScriptLanguage::reload_all_scripts() {
SelfList<GDScript> *elem = script_list.first();
while (elem) {
- if (elem->self()->get_path().is_resource_file()) {
+ // Scripts will reload all subclasses, so only reload root scripts.
+ if (elem->self()->is_root_script() && elem->self()->get_path().is_resource_file()) {
print_verbose("GDScript: Found: " + elem->self()->get_path());
scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
}
@@ -2193,7 +2195,8 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
SelfList<GDScript> *elem = script_list.first();
while (elem) {
- if (elem->self()->get_path().is_resource_file()) {
+ // Scripts will reload all subclasses, so only reload root scripts.
+ if (elem->self()->is_root_script() && elem->self()->get_path().is_resource_file()) {
scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
}
elem = elem->next();
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 2df89d812c..7911ea47ec 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -240,6 +240,7 @@ public:
virtual Error reload(bool p_keep_state = false) override;
virtual void set_path(const String &p_path, bool p_take_over = false) override;
+ String get_script_path() const;
Error load_source_code(const String &p_path);
Error load_byte_code(const String &p_path);
@@ -432,7 +433,7 @@ public:
csi.write[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0;
if (_call_stack[i].function) {
csi.write[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name();
- csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path();
+ csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_script_path();
}
}
return csi;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 663d72038d..9ec53b2b66 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -219,15 +219,76 @@ Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::C
return OK;
}
-Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive) {
- if (p_class->base_type.is_set()) {
- // Already resolved
+void GDScriptAnalyzer::get_class_node_current_scope_classes(GDScriptParser::ClassNode *p_node, List<GDScriptParser::ClassNode *> *p_list) {
+ if (p_list->find(p_node) != nullptr) {
+ return;
+ }
+ p_list->push_back(p_node);
+
+ // TODO: Try to solve class inheritance if not yet resolving.
+
+ // Prioritize node base type over its outer class
+ if (p_node->base_type.class_type != nullptr) {
+ get_class_node_current_scope_classes(p_node->base_type.class_type, p_list);
+ }
+
+ if (p_node->outer != nullptr) {
+ get_class_node_current_scope_classes(p_node->outer, p_list);
+ }
+}
+
+Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = p_class;
+ }
+
+ if (p_class->base_type.is_resolving()) {
+ push_error(vformat(R"(Could not resolve class "%s": Cyclic reference.)", type_from_metatype(p_class->get_datatype()).to_string()), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
+ if (!p_class->base_type.has_no_type()) {
+ // Already resolved.
+ return OK;
+ }
+
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not parse script "%s": %s.)", script_path, error_names[err]), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
+ ERR_FAIL_COND_V_MSG(!parser_ref->get_parser()->has_class(p_class), ERR_PARSE_ERROR, R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_inheritance(p_class);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve inheritance for class "%s".)", p_class->fqcn), p_source);
+ return ERR_PARSE_ERROR;
+ }
+
return OK;
}
+ GDScriptParser::ClassNode *previous_class = parser->current_class;
+ parser->current_class = p_class;
+
if (p_class->identifier) {
StringName class_name = p_class->identifier->name;
- if (class_exists(class_name)) {
+ if (GDScriptParser::get_builtin_type(class_name) < Variant::VARIANT_MAX) {
+ push_error(vformat(R"(Class "%s" hides a built-in type.)", class_name), p_class->identifier);
+ } else if (class_exists(class_name)) {
push_error(vformat(R"(Class "%s" hides a native class.)", class_name), p_class->identifier);
} else if (ScriptServer::is_global_class(class_name) && (ScriptServer::get_global_class_path(class_name) != parser->script_path || p_class != parser->head)) {
push_error(vformat(R"(Class "%s" hides a global script class.)", class_name), p_class->identifier);
@@ -236,7 +297,9 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
}
}
- GDScriptParser::DataType result;
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ p_class->base_type = resolving_datatype;
// Set datatype for class.
GDScriptParser::DataType class_type;
@@ -249,6 +312,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
class_type.builtin_type = Variant::OBJECT;
p_class->set_datatype(class_type);
+ GDScriptParser::DataType result;
if (!p_class->extends_used) {
result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
result.kind = GDScriptParser::DataType::NATIVE;
@@ -270,7 +334,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = ext_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ext_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", p_class->extends_path), p_class);
return err;
@@ -297,7 +361,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = base_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = base_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
@@ -306,7 +370,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
}
} else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) {
const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name);
- if (info.path.get_extension().to_lower() != ".gd") {
+ if (info.path.get_extension().to_lower() != GDScriptLanguage::get_singleton()->get_extension()) {
push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), p_class);
return ERR_PARSE_ERROR;
}
@@ -317,22 +381,24 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = info_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = info_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
+ base = info_parser->get_parser()->head->get_datatype();
} else if (class_exists(name) && ClassDB::can_instantiate(name)) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
// Look for other classes in script.
- GDScriptParser::ClassNode *look_class = p_class;
bool found = false;
- while (look_class != nullptr) {
+ List<GDScriptParser::ClassNode *> script_classes;
+ get_class_node_current_scope_classes(p_class, &script_classes);
+ for (GDScriptParser::ClassNode *look_class : script_classes) {
if (look_class->identifier && look_class->identifier->name == name) {
if (!look_class->get_datatype().is_set()) {
- Error err = resolve_inheritance(look_class, false);
+ Error err = resolve_class_inheritance(look_class, p_class);
if (err) {
return err;
}
@@ -341,19 +407,12 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
found = true;
break;
}
- if (look_class->members_indices.has(name) && look_class->get_member(name).type == GDScriptParser::ClassNode::Member::CLASS) {
- GDScriptParser::ClassNode::Member member = look_class->get_member(name);
- if (!member.m_class->get_datatype().is_set()) {
- Error err = resolve_inheritance(member.m_class, false);
- if (err) {
- return err;
- }
- }
- base = member.m_class->get_datatype();
+ if (look_class->has_member(name)) {
+ resolve_class_member(look_class, name, p_class);
+ base = look_class->get_member(name).get_datatype();
found = true;
break;
}
- look_class = look_class->outer;
}
if (!found) {
@@ -386,7 +445,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
result = base;
}
- if (!result.is_set()) {
+ if (!result.is_set() || result.has_no_type()) {
// TODO: More specific error messages.
push_error(vformat(R"(Could not resolve inheritance for class "%s".)", p_class->identifier == nullptr ? "<main>" : p_class->identifier->name), p_class);
return ERR_PARSE_ERROR;
@@ -406,10 +465,21 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
class_type.native_type = result.native_type;
p_class->set_datatype(class_type);
+ parser->current_class = previous_class;
+
+ return OK;
+}
+
+Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive) {
+ Error err = resolve_class_inheritance(p_class);
+ if (err) {
+ return err;
+ }
+
if (p_recursive) {
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type == GDScriptParser::ClassNode::Member::CLASS) {
- Error err = resolve_inheritance(p_class->members[i].m_class, true);
+ err = resolve_class_inheritance(p_class->members[i].m_class, true);
if (err) {
return err;
}
@@ -421,14 +491,29 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
}
GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::TypeNode *p_type) {
- GDScriptParser::DataType result;
+ GDScriptParser::DataType bad_type;
+ bad_type.kind = GDScriptParser::DataType::VARIANT;
+ bad_type.type_source = GDScriptParser::DataType::INFERRED;
if (p_type == nullptr) {
- result.kind = GDScriptParser::DataType::VARIANT;
- return result;
+ return bad_type;
+ }
+
+ if (p_type->get_datatype().is_resolving()) {
+ push_error(R"(Could not resolve datatype: Cyclic reference.)", p_type);
+ return bad_type;
+ }
+
+ if (!p_type->get_datatype().has_no_type()) {
+ return p_type->get_datatype();
}
- result.type_source = result.ANNOTATED_EXPLICIT;
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ p_type->set_datatype(resolving_datatype);
+
+ GDScriptParser::DataType result;
+ result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
result.builtin_type = Variant::OBJECT;
if (p_type->type_chain.is_empty()) {
@@ -442,29 +527,21 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
StringName first = p_type->type_chain[0]->name;
if (first == SNAME("Variant")) {
- result.kind = GDScriptParser::DataType::VARIANT;
if (p_type->type_chain.size() > 1) {
- push_error(R"("Variant" type don't contain nested types.)", p_type->type_chain[1]);
- return GDScriptParser::DataType();
+ // TODO: Variant does actually have a nested Type though.
+ push_error(R"(Variant doesn't contain nested types.)", p_type->type_chain[1]);
+ return bad_type;
}
- return result;
- }
-
- if (first == SNAME("Object")) {
+ result.kind = GDScriptParser::DataType::VARIANT;
+ } else if (first == SNAME("Object")) {
+ // Object is treated like a native type, not a built-in.
result.kind = GDScriptParser::DataType::NATIVE;
result.native_type = SNAME("Object");
- if (p_type->type_chain.size() > 1) {
- push_error(R"("Object" type don't contain nested types.)", p_type->type_chain[1]);
- return GDScriptParser::DataType();
- }
- return result;
- }
-
- if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
+ } else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
if (p_type->type_chain.size() > 1) {
push_error(R"(Built-in types don't contain nested types.)", p_type->type_chain[1]);
- return GDScriptParser::DataType();
+ return bad_type;
}
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = GDScriptParser::get_builtin_type(first);
@@ -490,9 +567,9 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
String ext = path.get_extension();
if (ext == GDScriptLanguage::get_singleton()->get_extension()) {
Ref<GDScriptParserRef> ref = get_parser_for(path);
- if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
result = ref->get_parser()->head->get_datatype();
} else {
@@ -507,9 +584,9 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
} else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) {
const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first);
Ref<GDScriptParserRef> ref = get_parser_for(autoload.path);
- if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse singleton "%s" from "%s".)", first, autoload.path), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
result = ref->get_parser()->head->get_datatype();
} else if (ClassDB::has_enum(parser->current_class->base_type.native_type, first)) {
@@ -517,38 +594,36 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = make_native_enum_type(parser->current_class->base_type.native_type, first);
} else {
// Classes in current scope.
- GDScriptParser::ClassNode *script_class = parser->current_class;
- bool found = false;
- while (!found && script_class != nullptr) {
+ List<GDScriptParser::ClassNode *> script_classes;
+ get_class_node_current_scope_classes(parser->current_class, &script_classes);
+ for (GDScriptParser::ClassNode *script_class : script_classes) {
if (script_class->identifier && script_class->identifier->name == first) {
result = script_class->get_datatype();
- found = true;
break;
}
if (script_class->members_indices.has(first)) {
- GDScriptParser::ClassNode::Member member = script_class->members[script_class->members_indices[first]];
+ resolve_class_member(script_class, first, p_type);
+
+ GDScriptParser::ClassNode::Member member = script_class->get_member(first);
switch (member.type) {
case GDScriptParser::ClassNode::Member::CLASS:
- result = member.m_class->get_datatype();
- found = true;
+ result = member.get_datatype();
break;
case GDScriptParser::ClassNode::Member::ENUM:
- result = member.m_enum->get_datatype();
- found = true;
+ result = member.get_datatype();
break;
case GDScriptParser::ClassNode::Member::CONSTANT:
- if (member.constant->get_datatype().is_meta_type) {
- result = member.constant->get_datatype();
+ if (member.get_datatype().is_meta_type) {
+ result = member.get_datatype();
result.is_meta_type = false;
- found = true;
break;
} else if (Ref<Script>(member.constant->initializer->reduced_value).is_valid()) {
Ref<GDScript> gdscript = member.constant->initializer->reduced_value;
if (gdscript.is_valid()) {
- Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_path());
- if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
- push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_path()), p_type);
- return GDScriptParser::DataType();
+ Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_script_path());
+ if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
+ push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_script_path()), p_type);
+ return bad_type;
}
result = ref->get_parser()->head->get_datatype();
result.is_meta_type = false;
@@ -566,16 +641,14 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
[[fallthrough]];
default:
push_error(vformat(R"("%s" is a %s but does not contain a type.)", first, member.get_type_name()), p_type);
- return GDScriptParser::DataType();
+ return bad_type;
}
}
- script_class = script_class->outer;
}
}
if (!result.is_set()) {
push_error(vformat(R"("%s" was not found in the current scope.)", first), p_type);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
}
if (p_type->type_chain.size() > 1) {
@@ -586,27 +659,26 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = p_type->type_chain[i]->get_datatype();
if (!result.is_set()) {
push_error(vformat(R"(Could not find type "%s" under base "%s".)", p_type->type_chain[i]->name, base.to_string()), p_type->type_chain[1]);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
} else if (!result.is_meta_type) {
push_error(vformat(R"(Member "%s" under base "%s" is not a valid type.)", p_type->type_chain[i]->name, base.to_string()), p_type->type_chain[1]);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
}
}
} else if (result.kind == GDScriptParser::DataType::NATIVE) {
// Only enums allowed for native.
- if (ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) {
- if (p_type->type_chain.size() > 2) {
- push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
- } else {
- result = make_native_enum_type(result.native_type, p_type->type_chain[1]->name);
- }
+ if (!ClassDB::has_enum(result.native_type, p_type->type_chain[1]->name)) {
+ push_error(vformat(R"(Could not find nested type "%s" under base "%s".)", p_type->type_chain[1]->name, result.to_string()), p_type->type_chain[1]);
+ return bad_type;
+ }
+ if (p_type->type_chain.size() > 2) {
+ push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
+ return bad_type;
}
+ result = make_native_enum_type(result.native_type, p_type->type_chain[1]->name);
} else {
push_error(vformat(R"(Could not find nested type "%s" under base "%s".)", p_type->type_chain[1]->name, result.to_string()), p_type->type_chain[1]);
- result.kind = GDScriptParser::DataType::VARIANT; // Leave Variant anyway so future type check don't use an unresolved type.
- return result;
+ return bad_type;
}
}
@@ -618,22 +690,77 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return result;
}
-void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_class) {
- if (p_class->resolved_interface) {
+void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, StringName p_name, const GDScriptParser::Node *p_source) {
+ ERR_FAIL_COND(!p_class->has_member(p_name));
+ resolve_class_member(p_class, p_class->members_indices[p_name], p_source);
+}
+
+void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, int p_index, const GDScriptParser::Node *p_source) {
+ ERR_FAIL_INDEX(p_index, p_class->members.size());
+
+ GDScriptParser::ClassNode::Member &member = p_class->members.write[p_index];
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = member.get_source_node();
+ }
+
+ if (member.get_datatype().is_resolving()) {
+ push_error(vformat(R"(Could not resolve member "%s": Cyclic reference.)", member.get_name()), p_source);
+ return;
+ }
+
+ if (member.get_datatype().is_set()) {
+ return;
+ }
+
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s" (While resolving "%s").)", script_path, member.get_name()), p_source);
+ return;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve script "%s": %s (While resolving "%s").)", script_path, error_names[err], member.get_name()), p_source);
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_member(p_class, p_index);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve member "%s".)", member.get_name()), p_source);
+ }
+
return;
}
- p_class->resolved_interface = true;
+
+ // If it's already resolving, that's ok.
+ if (!p_class->base_type.is_resolving()) {
+ Error err = resolve_class_inheritance(p_class);
+ if (err) {
+ return;
+ }
+ }
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
- for (int i = 0; i < p_class->members.size(); i++) {
- GDScriptParser::ClassNode::Member member = p_class->members[i];
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ {
switch (member.type) {
case GDScriptParser::ClassNode::Member::VARIABLE: {
check_class_member_name_conflict(p_class, member.variable->identifier->name, member.variable);
+ member.variable->set_datatype(resolving_datatype);
+
GDScriptParser::DataType datatype;
datatype.kind = GDScriptParser::DataType::VARIANT;
datatype.type_source = GDScriptParser::DataType::UNDETECTED;
@@ -645,7 +772,6 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
if (member.variable->initializer != nullptr) {
- member.variable->set_datatype(datatype); // Allow recursive usage.
reduce_expression(member.variable->initializer);
if ((member.variable->infer_datatype || (member.variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && member.variable->initializer->type == GDScriptParser::Node::ARRAY) {
// Typed array.
@@ -656,18 +782,14 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
}
datatype = member.variable->initializer->get_datatype();
+
if (datatype.type_source != GDScriptParser::DataType::UNDETECTED) {
datatype.type_source = GDScriptParser::DataType::INFERRED;
}
- }
- // Check if initializer is an unset identifier (ie: a variable within scope, but declared below)
- if (member.variable->initializer && !member.variable->initializer->get_datatype().is_set()) {
- if (member.variable->initializer->type == GDScriptParser::Node::IDENTIFIER) {
- GDScriptParser::IdentifierNode *initializer_identifier = static_cast<GDScriptParser::IdentifierNode *>(member.variable->initializer);
- push_error(vformat(R"(Identifier "%s" must be declared above current variable.)", initializer_identifier->name), member.variable->initializer);
- } else {
- ERR_PRINT("Parser bug (please report): tried to assign unset node without an identifier.");
+ if (!datatype.is_set()) {
+ push_error(vformat(R"(Could not resolve initializer for member "%s".)", member.variable->identifier->name), member.variable->initializer);
+ datatype.kind = GDScriptParser::DataType::VARIANT;
}
}
@@ -719,10 +841,9 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
case GDScriptParser::ClassNode::Member::CONSTANT: {
check_class_member_name_conflict(p_class, member.constant->identifier->name, member.constant);
- reduce_expression(member.constant->initializer);
+ member.constant->set_datatype(resolving_datatype);
GDScriptParser::DataType specified_type;
-
if (member.constant->datatype_specifier != nullptr) {
specified_type = resolve_datatype(member.constant->datatype_specifier);
specified_type.is_meta_type = false;
@@ -730,7 +851,9 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
GDScriptParser::DataType datatype;
if (member.constant->initializer) {
+ reduce_expression(member.constant->initializer);
datatype = member.constant->initializer->get_datatype();
+
if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer);
const_fold_array(array);
@@ -743,6 +866,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer));
}
+ if (!datatype.is_set()) {
+ push_error(vformat(R"(Could not resolve initializer for member "%s".)", member.constant->identifier->name), member.constant->initializer);
+ datatype.kind = GDScriptParser::DataType::VARIANT;
+ }
+
if (!member.constant->initializer->is_constant) {
push_error(R"(Initializer for a constant must be a constant expression.)", member.constant->initializer);
}
@@ -771,6 +899,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
case GDScriptParser::ClassNode::Member::SIGNAL: {
check_class_member_name_conflict(p_class, member.signal->identifier->name, member.signal);
+ member.signal->set_datatype(resolving_datatype);
+
for (int j = 0; j < member.signal->parameters.size(); j++) {
GDScriptParser::DataType signal_type = resolve_datatype(member.signal->parameters[j]->datatype_specifier);
signal_type.is_meta_type = false;
@@ -792,6 +922,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
case GDScriptParser::ClassNode::Member::ENUM: {
check_class_member_name_conflict(p_class, member.m_enum->identifier->name, member.m_enum);
+ member.m_enum->set_datatype(resolving_datatype);
+
GDScriptParser::DataType enum_type;
enum_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
enum_type.kind = GDScriptParser::DataType::ENUM;
@@ -801,7 +933,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
enum_type.is_meta_type = true;
enum_type.is_constant = true;
- // Enums can't be nested, so we can safely override this.
+ const GDScriptParser::EnumNode *prev_enum = current_enum;
current_enum = member.m_enum;
for (int j = 0; j < member.m_enum->values.size(); j++) {
@@ -829,7 +961,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
enum_type.enum_values[element.identifier->name] = element.value;
}
- current_enum = nullptr;
+ current_enum = prev_enum;
member.m_enum->set_datatype(enum_type);
@@ -839,15 +971,18 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
} break;
case GDScriptParser::ClassNode::Member::FUNCTION:
- resolve_function_signature(member.function);
+ resolve_function_signature(member.function, p_source);
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
if (member.enum_value.custom_value) {
check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.custom_value);
+ member.enum_value.identifier->set_datatype(resolving_datatype);
+
+ const GDScriptParser::EnumNode *prev_enum = current_enum;
current_enum = member.enum_value.parent_enum;
reduce_expression(member.enum_value.custom_value);
- current_enum = nullptr;
+ current_enum = prev_enum;
if (!member.enum_value.custom_value->is_constant) {
push_error(R"(Enum values must be constant.)", member.enum_value.custom_value);
@@ -867,12 +1002,22 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
member.enum_value.resolved = true;
}
+
// Also update the original references.
- member.enum_value.parent_enum->values.write[member.enum_value.index] = member.enum_value;
- p_class->members.write[i].enum_value = member.enum_value;
+ member.enum_value.parent_enum->values.set(member.enum_value.index, member.enum_value);
+
+ GDScriptParser::DataType datatype;
+ datatype.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ datatype.kind = GDScriptParser::DataType::BUILTIN;
+ datatype.builtin_type = Variant::INT;
+ member.enum_value.identifier->set_datatype(datatype);
} break;
case GDScriptParser::ClassNode::Member::CLASS:
check_class_member_name_conflict(p_class, member.m_class->identifier->name, member.m_class);
+ // If it's already resolving, that's ok.
+ if (!member.m_class->base_type.is_resolving()) {
+ resolve_class_inheritance(member.m_class, p_source);
+ }
break;
case GDScriptParser::ClassNode::Member::GROUP:
// No-op, but needed to silence warnings.
@@ -883,28 +1028,123 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
}
- // Recurse nested classes.
- for (int i = 0; i < p_class->members.size(); i++) {
- GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::CLASS) {
- continue;
+ parser->current_class = previous_class;
+}
+
+void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = p_class;
+ }
+
+ if (!p_class->resolved_interface) {
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ return;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve script "%s": %s.)", script_path, error_names[err]), p_source);
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_interface(p_class);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve class "%s".)", p_class->fqcn), p_source);
+ }
+
+ return;
+ }
+ p_class->resolved_interface = true;
+
+ if (resolve_class_inheritance(p_class) != OK) {
+ return;
}
- resolve_class_interface(member.m_class);
+ GDScriptParser::DataType base_type = p_class->base_type;
+ if (base_type.kind == GDScriptParser::DataType::CLASS) {
+ GDScriptParser::ClassNode *base_class = base_type.class_type;
+ resolve_class_interface(base_class, p_class);
+ }
+
+ for (int i = 0; i < p_class->members.size(); i++) {
+ resolve_class_member(p_class, i);
+ }
}
+}
- parser->current_class = previous_class;
+void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_class, bool p_recursive) {
+ resolve_class_interface(p_class);
+
+ if (p_recursive) {
+ for (int i = 0; i < p_class->members.size(); i++) {
+ GDScriptParser::ClassNode::Member member = p_class->members[i];
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ resolve_class_interface(member.m_class, true);
+ }
+ }
+ }
}
-void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
+void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr && parser->has_class(p_class)) {
+ p_source = p_class;
+ }
+
if (p_class->resolved_body) {
return;
}
+
+ if (!parser->has_class(p_class)) {
+ String script_path = p_class->get_datatype().script_path;
+ Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
+ if (parser_ref.is_null()) {
+ push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
+ return;
+ }
+
+ Error err = parser_ref->raise_status(GDScriptParserRef::PARSED);
+ if (err) {
+ push_error(vformat(R"(Could not resolve script "%s": %s.)", script_path, error_names[err]), p_source);
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");
+
+ GDScriptAnalyzer *other_analyzer = parser_ref->get_analyzer();
+ GDScriptParser *other_parser = parser_ref->get_parser();
+
+ int error_count = other_parser->errors.size();
+ other_analyzer->resolve_class_body(p_class);
+ if (other_parser->errors.size() > error_count) {
+ push_error(vformat(R"(Could not resolve class "%s".)", p_class->fqcn), p_source);
+ }
+
+ return;
+ }
+
p_class->resolved_body = true;
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
+ resolve_class_interface(p_class, p_source);
+
+ GDScriptParser::DataType base_type = p_class->base_type;
+ if (base_type.kind == GDScriptParser::DataType::CLASS) {
+ GDScriptParser::ClassNode *base_class = base_type.class_type;
+ resolve_class_body(base_class, p_class);
+ }
+
// Do functions and properties now.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
@@ -947,18 +1187,6 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
}
- parser->current_class = previous_class;
-
- // Recurse nested classes.
- for (int i = 0; i < p_class->members.size(); i++) {
- GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::CLASS) {
- continue;
- }
-
- resolve_class_body(member.m_class);
- }
-
// Check unused variables and datatypes of property getters and setters.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
@@ -1046,6 +1274,21 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
}
}
+
+ parser->current_class = previous_class;
+}
+
+void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, bool p_recursive) {
+ resolve_class_body(p_class);
+
+ if (p_recursive) {
+ for (int i = 0; i < p_class->members.size(); i++) {
+ GDScriptParser::ClassNode::Member member = p_class->members[i];
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ resolve_class_body(member.m_class, true);
+ }
+ }
+ }
}
void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node, bool p_is_root) {
@@ -1055,8 +1298,10 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node, bool p_is_root
case GDScriptParser::Node::NONE:
break; // Unreachable.
case GDScriptParser::Node::CLASS:
- resolve_class_interface(static_cast<GDScriptParser::ClassNode *>(p_node));
- resolve_class_body(static_cast<GDScriptParser::ClassNode *>(p_node));
+ if (OK == resolve_class_inheritance(static_cast<GDScriptParser::ClassNode *>(p_node), true)) {
+ resolve_class_interface(static_cast<GDScriptParser::ClassNode *>(p_node), true);
+ resolve_class_body(static_cast<GDScriptParser::ClassNode *>(p_node), true);
+ }
break;
case GDScriptParser::Node::CONSTANT:
resolve_constant(static_cast<GDScriptParser::ConstantNode *>(p_node));
@@ -1138,7 +1383,16 @@ void GDScriptAnalyzer::resolve_annotation(GDScriptParser::AnnotationNode *p_anno
// TODO: Add second validation function for annotations, so they can use checked types.
}
-void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *p_function) {
+void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *p_function, const GDScriptParser::Node *p_source) {
+ if (p_source == nullptr) {
+ p_source = p_function;
+ }
+
+ if (p_function->get_datatype().is_resolving()) {
+ push_error(vformat(R"(Could not resolve function "%s": Cyclic reference.)", p_function->identifier->name), p_source);
+ return;
+ }
+
if (p_function->resolved_signature) {
return;
}
@@ -1147,6 +1401,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
GDScriptParser::FunctionNode *previous_function = parser->current_function;
parser->current_function = p_function;
+ GDScriptParser::DataType prev_datatype = p_function->get_datatype();
+
+ GDScriptParser::DataType resolving_datatype;
+ resolving_datatype.kind = GDScriptParser::DataType::RESOLVING;
+ p_function->set_datatype(resolving_datatype);
+
#ifdef TOOLS_ENABLED
int default_value_count = 0;
#endif // TOOLS_ENABLED
@@ -1251,6 +1511,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
#endif // TOOLS_ENABLED
}
+ if (p_function->get_datatype().is_resolving()) {
+ p_function->set_datatype(prev_datatype);
+ }
+
parser->current_function = previous_function;
}
@@ -1584,7 +1848,7 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
}
if (p_constant->datatype_specifier != nullptr) {
- if (!is_type_compatible(explicit_type, type)) {
+ if (!is_type_compatible(explicit_type, type, true)) {
push_error(vformat(R"(Assigned value for constant "%s" has type %s which is not compatible with defined type %s.)", p_constant->identifier->name, type.to_string(), explicit_type.to_string()), p_constant->initializer);
#ifdef DEBUG_ENABLED
} else if (explicit_type.builtin_type == Variant::INT && type.builtin_type == Variant::FLOAT) {
@@ -2160,7 +2424,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
GDScriptParser::DataType test_type = right_type;
test_type.is_meta_type = false;
- if (!is_type_compatible(test_type, p_binary_op->left_operand->get_datatype(), false)) {
+ if (!is_type_compatible(test_type, left_type, false)) {
push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)"), p_binary_op->left_operand);
p_binary_op->reduced_value = false;
} else {
@@ -2194,11 +2458,11 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
GDScriptParser::DataType test_type = right_type;
test_type.is_meta_type = false;
- if (!is_type_compatible(test_type, p_binary_op->left_operand->get_datatype(), false)) {
+ if (!is_type_compatible(test_type, left_type, false)) {
// Test reverse as well to consider for subtypes.
- if (!is_type_compatible(p_binary_op->left_operand->get_datatype(), test_type, false)) {
- if (p_binary_op->left_operand->get_datatype().is_hard_type()) {
- push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", p_binary_op->left_operand->get_datatype().to_string(), test_type.to_string()), p_binary_op->left_operand);
+ if (!is_type_compatible(left_type, test_type, false)) {
+ if (left_type.is_hard_type()) {
+ push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", left_type.to_string(), test_type.to_string()), p_binary_op->left_operand);
} else {
// TODO: Warning.
mark_node_unsafe(p_binary_op);
@@ -2676,7 +2940,7 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
}
void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
- HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, VariantComparator> elements;
+ HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, StringLikeVariantComparator> elements;
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
@@ -2734,7 +2998,7 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str
return type;
}
- Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err) {
push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source);
type.type_source = GDScriptParser::DataType::UNDETECTED;
@@ -2757,6 +3021,10 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str
}
void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base) {
+ if (!p_identifier->get_datatype().has_no_type()) {
+ return;
+ }
+
GDScriptParser::DataType base;
if (p_base == nullptr) {
base = type_from_metatype(parser->current_class->get_datatype());
@@ -2849,16 +3117,16 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->set_datatype(base_class->get_datatype());
return;
}
+
if (base_class->has_member(name)) {
- const GDScriptParser::ClassNode::Member &member = base_class->get_member(name);
+ resolve_class_member(base_class, name, p_identifier);
+
+ GDScriptParser::ClassNode::Member member = base_class->get_member(name);
p_identifier->set_datatype(member.get_datatype());
switch (member.type) {
case GDScriptParser::ClassNode::Member::CONSTANT:
- // For out-of-order resolution:
- reduce_expression(member.constant->initializer);
p_identifier->is_constant = true;
p_identifier->reduced_value = member.constant->initializer->reduced_value;
- p_identifier->set_datatype(member.constant->initializer->get_datatype());
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
p_identifier->constant_source = member.constant;
break;
@@ -2876,14 +3144,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_SIGNAL;
break;
case GDScriptParser::ClassNode::Member::FUNCTION:
- resolve_function_signature(member.function);
p_identifier->set_datatype(make_callable_type(member.function->info));
break;
- case GDScriptParser::ClassNode::Member::CLASS:
- // For out-of-order resolution:
- resolve_class_interface(member.m_class);
- p_identifier->set_datatype(member.m_class->get_datatype());
- break;
default:
break; // Type already set.
}
@@ -2891,41 +3153,38 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
// Check outer constants.
// TODO: Allow outer static functions.
- GDScriptParser::ClassNode *outer = base_class->outer;
- while (outer != nullptr) {
- if (outer->has_member(name)) {
- const GDScriptParser::ClassNode::Member &member = outer->get_member(name);
- switch (member.type) {
- case GDScriptParser::ClassNode::Member::CONSTANT: {
- // TODO: Make sure loops won't cause problem. And make special error message for those.
- // For out-of-order resolution:
- reduce_expression(member.constant->initializer);
- p_identifier->set_datatype(member.get_datatype());
- p_identifier->is_constant = true;
- p_identifier->reduced_value = member.constant->initializer->reduced_value;
- return;
- } break;
- case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
- p_identifier->set_datatype(member.get_datatype());
- p_identifier->is_constant = true;
- p_identifier->reduced_value = member.enum_value.value;
- return;
- } break;
- case GDScriptParser::ClassNode::Member::ENUM: {
- p_identifier->set_datatype(member.get_datatype());
- p_identifier->is_constant = false;
- return;
- } break;
- case GDScriptParser::ClassNode::Member::CLASS: {
- resolve_class_interface(member.m_class);
- p_identifier->set_datatype(member.m_class->get_datatype());
- return;
- } break;
- default:
- break;
+ if (base_class->outer != nullptr) {
+ List<GDScriptParser::ClassNode *> script_classes;
+ get_class_node_current_scope_classes(parser->current_class, &script_classes);
+ for (GDScriptParser::ClassNode *script_class : script_classes) {
+ if (script_class->has_member(name)) {
+ resolve_class_member(script_class, name, p_identifier);
+
+ GDScriptParser::ClassNode::Member member = script_class->get_member(name);
+ switch (member.type) {
+ case GDScriptParser::ClassNode::Member::CONSTANT:
+ // TODO: Make sure loops won't cause problem. And make special error message for those.
+ p_identifier->set_datatype(member.get_datatype());
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.constant->initializer->reduced_value;
+ return;
+ case GDScriptParser::ClassNode::Member::ENUM_VALUE:
+ p_identifier->set_datatype(member.get_datatype());
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.enum_value.value;
+ return;
+ case GDScriptParser::ClassNode::Member::ENUM:
+ p_identifier->set_datatype(member.get_datatype());
+ p_identifier->is_constant = false;
+ return;
+ case GDScriptParser::ClassNode::Member::CLASS:
+ p_identifier->set_datatype(member.get_datatype());
+ return;
+ default:
+ break;
+ }
}
}
- outer = outer->outer;
}
base_class = base_class->base_type.class_type;
@@ -3126,7 +3385,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
if (ResourceLoader::get_resource_type(autoload.path) == "GDScript") {
Ref<GDScriptParserRef> singl_parser = get_parser_for(autoload.path);
if (singl_parser.is_valid()) {
- Error err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = singl_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err == OK) {
result = type_from_metatype(singl_parser->get_parser()->head->get_datatype());
}
@@ -3136,11 +3395,11 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
Variant constant = GDScriptLanguage::get_singleton()->get_named_globals_map()[name];
Node *node = Object::cast_to<Node>(constant);
if (node != nullptr) {
- Ref<Script> scr = node->get_script();
+ Ref<GDScript> scr = node->get_script();
if (scr.is_valid()) {
- Ref<GDScriptParserRef> singl_parser = get_parser_for(scr->get_path());
+ Ref<GDScriptParserRef> singl_parser = get_parser_for(scr->get_script_path());
if (singl_parser.is_valid()) {
- Error err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = singl_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err == OK) {
result = type_from_metatype(singl_parser->get_parser()->head->get_datatype());
}
@@ -3332,54 +3591,44 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
if (p_subscript->attribute == nullptr) {
return;
}
- if (p_subscript->base->is_constant) {
+
+ GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
+ bool valid = false;
+ // If the base is a metatype, use the analyzer instead.
+ if (p_subscript->base->is_constant && !base_type.is_meta_type) {
// Just try to get it.
- bool valid = false;
Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
-
- // If it's a GDScript instance, try to get the full script. Maybe it's not still completely loaded.
- Ref<GDScript> gdscr = Ref<GDScript>(p_subscript->base->reduced_value);
- if (!valid && gdscr.is_valid()) {
- Error err = OK;
- GDScriptCache::get_full_script(gdscr->get_path(), err);
- if (err == OK) {
- value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
- }
- }
-
- if (!valid) {
- push_error(vformat(R"(Cannot get member "%s" from "%s".)", p_subscript->attribute->name, p_subscript->base->reduced_value), p_subscript->index);
- result_type.kind = GDScriptParser::DataType::VARIANT;
- } else {
+ if (valid) {
p_subscript->is_constant = true;
p_subscript->reduced_value = value;
result_type = type_from_variant(value, p_subscript);
}
+ } else if (base_type.is_variant() || !base_type.is_hard_type()) {
+ valid = true;
+ result_type.kind = GDScriptParser::DataType::VARIANT;
+ mark_node_unsafe(p_subscript);
} else {
- GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
-
- if (base_type.is_variant() || !base_type.is_hard_type()) {
- result_type.kind = GDScriptParser::DataType::VARIANT;
- mark_node_unsafe(p_subscript);
- } else {
- reduce_identifier_from_base(p_subscript->attribute, &base_type);
- GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype();
- if (attr_type.is_set()) {
- result_type = attr_type;
- p_subscript->is_constant = p_subscript->attribute->is_constant;
- p_subscript->reduced_value = p_subscript->attribute->reduced_value;
- } else {
- if (base_type.kind == GDScriptParser::DataType::BUILTIN) {
- push_error(vformat(R"(Cannot find member "%s" in base "%s".)", p_subscript->attribute->name, base_type.to_string()), p_subscript->attribute);
+ reduce_identifier_from_base(p_subscript->attribute, &base_type);
+ GDScriptParser::DataType attr_type = p_subscript->attribute->get_datatype();
+ if (attr_type.is_set()) {
+ valid = true;
+ result_type = attr_type;
+ p_subscript->is_constant = p_subscript->attribute->is_constant;
+ p_subscript->reduced_value = p_subscript->attribute->reduced_value;
+ } else if (!base_type.is_constant) {
+ valid = base_type.kind != GDScriptParser::DataType::BUILTIN;
#ifdef DEBUG_ENABLED
- } else {
- parser->push_warning(p_subscript, GDScriptWarning::UNSAFE_PROPERTY_ACCESS, p_subscript->attribute->name, base_type.to_string());
-#endif
- }
- result_type.kind = GDScriptParser::DataType::VARIANT;
+ if (valid) {
+ parser->push_warning(p_subscript, GDScriptWarning::UNSAFE_PROPERTY_ACCESS, p_subscript->attribute->name, base_type.to_string());
}
+#endif
+ result_type.kind = GDScriptParser::DataType::VARIANT;
}
}
+ if (!valid) {
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".)", p_subscript->attribute->name, type_from_metatype(base_type).to_string()), p_subscript->attribute);
+ result_type.kind = GDScriptParser::DataType::VARIANT;
+ }
} else {
if (p_subscript->index == nullptr) {
return;
@@ -3432,7 +3681,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::QUATERNION:
case Variant::AABB:
case Variant::OBJECT:
- error = index_type.builtin_type != Variant::STRING;
+ error = index_type.builtin_type != Variant::STRING && index_type.builtin_type != Variant::STRING_NAME;
break;
// Expect String or number.
case Variant::BASIS:
@@ -3446,11 +3695,11 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::TRANSFORM3D:
case Variant::PROJECTION:
error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::FLOAT &&
- index_type.builtin_type != Variant::STRING;
+ index_type.builtin_type != Variant::STRING && index_type.builtin_type != Variant::STRING_NAME;
break;
// Expect String or int.
case Variant::COLOR:
- error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::STRING;
+ error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::STRING && index_type.builtin_type != Variant::STRING_NAME;
break;
// Don't support indexing, but we will check it later.
case Variant::RID:
@@ -3626,6 +3875,7 @@ void GDScriptAnalyzer::reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternar
void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op) {
reduce_expression(p_unary_op->operand);
+ GDScriptParser::DataType operand_type = p_unary_op->operand->get_datatype();
GDScriptParser::DataType result;
if (p_unary_op->operand == nullptr) {
@@ -3638,15 +3888,17 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
p_unary_op->is_constant = true;
p_unary_op->reduced_value = Variant::evaluate(p_unary_op->variant_op, p_unary_op->operand->reduced_value, Variant());
result = type_from_variant(p_unary_op->reduced_value, p_unary_op);
- } else if (p_unary_op->operand->get_datatype().is_variant()) {
+ }
+
+ if (operand_type.is_variant()) {
result.kind = GDScriptParser::DataType::VARIANT;
mark_node_unsafe(p_unary_op);
} else {
bool valid = false;
- result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), valid, p_unary_op);
+ result = get_operation_type(p_unary_op->variant_op, operand_type, valid, p_unary_op);
if (!valid) {
- push_error(vformat(R"(Invalid operand of type "%s" for unary operator "%s".)", p_unary_op->operand->get_datatype().to_string(), Variant::get_operator_name(p_unary_op->variant_op)), p_unary_op->operand);
+ push_error(vformat(R"(Invalid operand of type "%s" for unary operator "%s".)", operand_type.to_string(), Variant::get_operator_name(p_unary_op->variant_op)), p_unary_op);
}
}
@@ -3714,7 +3966,13 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
result.builtin_type = p_value.get_type();
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type.
- if (p_value.get_type() == Variant::OBJECT) {
+ if (p_value.get_type() == Variant::NIL) {
+ // A null value is a variant, not void.
+ result.kind = GDScriptParser::DataType::VARIANT;
+ } else if (p_value.get_type() == Variant::OBJECT) {
+ // Object is treated as a native type, not a builtin type.
+ result.kind = GDScriptParser::DataType::NATIVE;
+
Object *obj = p_value;
if (!obj) {
return GDScriptParser::DataType();
@@ -3729,7 +3987,6 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
scr = obj->get_script();
}
if (scr.is_valid()) {
- result.script_type = scr;
result.script_path = scr->get_path();
Ref<GDScript> gds = scr;
if (gds.is_valid()) {
@@ -3751,21 +4008,30 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
error_type.kind = GDScriptParser::DataType::VARIANT;
return error_type;
}
- ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
GDScriptParser::ClassNode *found = ref->get_parser()->head;
- // It should be okay to assume this exists, since we have a complete script already.
for (const StringName &E : class_chain) {
+ if (!found->has_member(E)) {
+ return GDScriptParser::DataType();
+ }
+
+ if (found->get_member(E).type != GDScriptParser::ClassNode::Member::CLASS) {
+ return GDScriptParser::DataType();
+ }
+
+ resolve_class_member(found, E, p_source);
+
found = found->get_member(E).m_class;
}
- result.class_type = found;
- result.script_path = ref->get_parser()->script_path;
+ result = found->get_datatype();
} else {
result.kind = GDScriptParser::DataType::SCRIPT;
+ result.native_type = scr->get_instance_base_type();
}
- result.native_type = scr->get_instance_base_type();
+ result.script_type = scr;
} else {
result.kind = GDScriptParser::DataType::NATIVE;
if (result.native_type == GDScriptNativeClass::get_class_static()) {
@@ -3889,8 +4155,12 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
push_error(vformat(R"(Member "%s" is not a function.)", function_name), p_source);
return false;
}
+
+ resolve_class_member(base_class, function_name, p_source);
found_function = base_class->get_member(function_name).function;
}
+
+ resolve_class_inheritance(base_class, p_source);
base_class = base_class->base_type.class_type;
}
@@ -4059,12 +4329,10 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
base_class = base_class->base_type.class_type;
}
- StringName base_native = base.native_type;
-
- ERR_FAIL_COND_V_MSG(!class_exists(base_native), false, "Non-existent native base class.");
-
- StringName parent = base_native;
+ StringName parent = base.native_type;
while (parent != StringName()) {
+ ERR_FAIL_COND_V_MSG(!class_exists(parent), false, "Non-existent native base class.");
+
if (ClassDB::has_method(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
return true;
@@ -4179,7 +4447,7 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
// Variant array can't be appended to typed array.
valid = false;
} else {
- valid = is_type_compatible(p_target.get_container_element_type(), p_source.get_container_element_type(), false);
+ valid = is_type_compatible(p_target.get_container_element_type(), p_source.get_container_element_type(), p_allow_implicit_conversion);
}
}
}
@@ -4254,6 +4522,7 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
case GDScriptParser::DataType::VARIANT:
case GDScriptParser::DataType::BUILTIN:
case GDScriptParser::DataType::ENUM:
+ case GDScriptParser::DataType::RESOLVING:
case GDScriptParser::DataType::UNRESOLVED:
break; // Already solved before.
}
@@ -4290,6 +4559,7 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
case GDScriptParser::DataType::VARIANT:
case GDScriptParser::DataType::BUILTIN:
case GDScriptParser::DataType::ENUM:
+ case GDScriptParser::DataType::RESOLVING:
case GDScriptParser::DataType::UNRESOLVED:
break; // Already solved before.
}
@@ -4304,6 +4574,10 @@ void GDScriptAnalyzer::push_error(const String &p_message, const GDScriptParser:
void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
#ifdef DEBUG_ENABLED
+ if (p_node == nullptr) {
+ return;
+ }
+
for (int i = p_node->start_line; i <= p_node->end_line; i++) {
parser->unsafe_lines.insert(i);
}
@@ -4336,39 +4610,46 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {
}
Error GDScriptAnalyzer::resolve_inheritance() {
- return resolve_inheritance(parser->head);
+ return resolve_class_inheritance(parser->head, true);
}
Error GDScriptAnalyzer::resolve_interface() {
- resolve_class_interface(parser->head);
+ resolve_class_interface(parser->head, true);
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::resolve_body() {
- resolve_class_body(parser->head);
+ resolve_class_body(parser->head, true);
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
-Error GDScriptAnalyzer::resolve_program() {
- resolve_class_interface(parser->head);
- resolve_class_body(parser->head);
-
+Error GDScriptAnalyzer::resolve_dependencies() {
for (KeyValue<String, Ref<GDScriptParserRef>> &K : depended_parsers) {
if (K.value.is_null()) {
return ERR_PARSE_ERROR;
}
- K.value->raise_status(GDScriptParserRef::FULLY_SOLVED);
+ K.value->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
}
+
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
Error GDScriptAnalyzer::analyze() {
parser->errors.clear();
- Error err = resolve_inheritance(parser->head);
+ Error err = OK;
+
+ err = resolve_inheritance();
if (err) {
return err;
}
- return resolve_program();
+
+ resolve_interface();
+ resolve_body();
+ if (!parser->errors.is_empty()) {
+ return ERR_PARSE_ERROR;
+ }
+
+ return resolve_dependencies();
}
GDScriptAnalyzer::GDScriptAnalyzer(GDScriptParser *p_parser) {
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 23a3ad39a5..a4d9efb094 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -50,18 +50,22 @@ class GDScriptAnalyzer {
Error check_native_member_name_conflict(const StringName &p_member_name, const GDScriptParser::Node *p_member_node, const StringName &p_native_type_string);
Error check_class_member_name_conflict(const GDScriptParser::ClassNode *p_class_node, const StringName &p_member_name, const GDScriptParser::Node *p_member_node);
- Error resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive = true);
+ void get_class_node_current_scope_classes(GDScriptParser::ClassNode *p_node, List<GDScriptParser::ClassNode *> *p_list);
+
+ Error resolve_class_inheritance(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr);
+ Error resolve_class_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive);
GDScriptParser::DataType resolve_datatype(GDScriptParser::TypeNode *p_type);
void decide_suite_type(GDScriptParser::Node *p_suite, GDScriptParser::Node *p_statement);
- // This traverses the tree to resolve all TypeNodes.
- Error resolve_program();
-
void resolve_annotation(GDScriptParser::AnnotationNode *p_annotation);
- void resolve_class_interface(GDScriptParser::ClassNode *p_class);
- void resolve_class_body(GDScriptParser::ClassNode *p_class);
- void resolve_function_signature(GDScriptParser::FunctionNode *p_function);
+ void resolve_class_member(GDScriptParser::ClassNode *p_class, StringName p_name, const GDScriptParser::Node *p_source = nullptr);
+ void resolve_class_member(GDScriptParser::ClassNode *p_class, int p_index, const GDScriptParser::Node *p_source = nullptr);
+ void resolve_class_interface(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr);
+ void resolve_class_interface(GDScriptParser::ClassNode *p_class, bool p_recursive);
+ void resolve_class_body(GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_source = nullptr);
+ void resolve_class_body(GDScriptParser::ClassNode *p_class, bool p_recursive);
+ void resolve_function_signature(GDScriptParser::FunctionNode *p_function, const GDScriptParser::Node *p_source = nullptr);
void resolve_function_body(GDScriptParser::FunctionNode *p_function);
void resolve_node(GDScriptParser::Node *p_node, bool p_is_root = true);
void resolve_suite(GDScriptParser::SuiteNode *p_suite);
@@ -113,7 +117,7 @@ class GDScriptAnalyzer {
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source);
void update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
- void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
+ void push_error(const String &p_message, const GDScriptParser::Node *p_origin = nullptr);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
void mark_lambda_use_self();
bool class_exists(const StringName &p_class) const;
@@ -126,6 +130,7 @@ public:
Error resolve_inheritance();
Error resolve_interface();
Error resolve_body();
+ Error resolve_dependencies();
Error analyze();
GDScriptAnalyzer(GDScriptParser *p_parser);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index fa158591fd..1bc83fbbb5 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -164,7 +164,7 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName
function->name = p_function_name;
function->_script = p_script;
- function->source = p_script->get_path();
+ function->source = p_script->get_script_path();
#ifdef DEBUG_ENABLED
function->func_cname = (String(function->source) + " - " + String(p_function_name)).utf8();
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 699ce67933..6faf2dde73 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -50,6 +50,13 @@ GDScriptParser *GDScriptParserRef::get_parser() const {
return parser;
}
+GDScriptAnalyzer *GDScriptParserRef::get_analyzer() {
+ if (analyzer == nullptr) {
+ analyzer = memnew(GDScriptAnalyzer(parser));
+ }
+ return analyzer;
+}
+
Error GDScriptParserRef::raise_status(Status p_new_status) {
ERR_FAIL_COND_V(parser == nullptr, ERR_INVALID_DATA);
@@ -64,23 +71,22 @@ Error GDScriptParserRef::raise_status(Status p_new_status) {
result = parser->parse(GDScriptCache::get_source_code(path), path, false);
break;
case PARSED: {
- analyzer = memnew(GDScriptAnalyzer(parser));
status = INHERITANCE_SOLVED;
- Error inheritance_result = analyzer->resolve_inheritance();
+ Error inheritance_result = get_analyzer()->resolve_inheritance();
if (result == OK) {
result = inheritance_result;
}
} break;
case INHERITANCE_SOLVED: {
status = INTERFACE_SOLVED;
- Error interface_result = analyzer->resolve_interface();
+ Error interface_result = get_analyzer()->resolve_interface();
if (result == OK) {
result = interface_result;
}
} break;
case INTERFACE_SOLVED: {
status = FULLY_SOLVED;
- Error body_result = analyzer->resolve_body();
+ Error body_result = get_analyzer()->resolve_body();
if (result == OK) {
result = body_result;
}
@@ -128,6 +134,10 @@ void GDScriptCache::move_script(const String &p_from, const String &p_to) {
MutexLock lock(singleton->mutex);
+ if (singleton->cleared) {
+ return;
+ }
+
for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) {
if (E.value.has(p_from)) {
E.value.insert(p_to);
@@ -158,6 +168,10 @@ void GDScriptCache::remove_script(const String &p_path) {
MutexLock lock(singleton->mutex);
+ if (singleton->cleared) {
+ return;
+ }
+
for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) {
if (!E.value.has(p_path)) {
continue;
@@ -371,6 +385,10 @@ void GDScriptCache::clear_unreferenced_packed_scenes() {
MutexLock lock(singleton->mutex);
+ if (singleton->cleared) {
+ return;
+ }
+
for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) {
if (E.value.size() > 0 || !ResourceLoader::is_imported(E.key)) {
continue;
@@ -388,6 +406,11 @@ void GDScriptCache::clear() {
MutexLock lock(singleton->mutex);
+ if (singleton->cleared) {
+ return;
+ }
+ singleton->cleared = true;
+
RBSet<Ref<GDScriptParserRef>> parser_map_refs;
for (KeyValue<String, GDScriptParserRef *> &E : singleton->parser_map) {
parser_map_refs.insert(E.value);
@@ -398,6 +421,9 @@ void GDScriptCache::clear() {
E->clear();
}
+ singleton->packed_scene_dependencies.clear();
+ singleton->packed_scene_cache.clear();
+
parser_map_refs.clear();
singleton->parser_map.clear();
singleton->shallow_gdscript_cache.clear();
@@ -412,7 +438,8 @@ GDScriptCache::GDScriptCache() {
}
GDScriptCache::~GDScriptCache() {
- destructing = true;
- clear();
+ if (!cleared) {
+ clear();
+ }
singleton = nullptr;
}
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index e7e1901d5d..43a45bfef6 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -65,6 +65,7 @@ public:
bool is_valid() const;
Status get_status() const;
GDScriptParser *get_parser() const;
+ GDScriptAnalyzer *get_analyzer();
Error raise_status(Status p_new_status);
void clear();
@@ -87,7 +88,7 @@ class GDScriptCache {
static GDScriptCache *singleton;
- bool destructing = false;
+ bool cleared = false;
Mutex mutex;
@@ -104,13 +105,6 @@ public:
static Ref<PackedScene> get_packed_scene(const String &p_path, Error &r_error, const String &p_owner = "");
static void clear_unreferenced_packed_scenes();
- static bool is_destructing() {
- if (singleton == nullptr) {
- return true;
- }
- return singleton->destructing;
- };
-
static void clear();
GDScriptCache();
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index ea93e1ebfc..4740b9b5a9 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -157,6 +157,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.builtin_type = Variant::INT;
}
break;
+ case GDScriptParser::DataType::RESOLVING:
case GDScriptParser::DataType::UNRESOLVED: {
ERR_PRINT("Parser bug: converting unresolved type.");
return GDScriptDataType();
@@ -1256,9 +1257,30 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
equality_type.kind = GDScriptDataType::BUILTIN;
equality_type.builtin_type = Variant::BOOL;
+ GDScriptCodeGenerator::Address type_string_addr = codegen.add_constant(Variant::STRING);
+ GDScriptCodeGenerator::Address type_string_name_addr = codegen.add_constant(Variant::STRING_NAME);
+
// Check type equality.
GDScriptCodeGenerator::Address type_equality_addr = codegen.add_temporary(equality_type);
codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
+
+ // Check if StringName <-> String comparison is possible.
+ GDScriptCodeGenerator::Address type_comp_addr_1 = codegen.add_temporary(equality_type);
+ GDScriptCodeGenerator::Address type_comp_addr_2 = codegen.add_temporary(equality_type);
+
+ codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_EQUAL, p_type_addr, type_string_addr);
+ codegen.generator->write_binary_operator(type_comp_addr_2, Variant::OP_EQUAL, literal_type_addr, type_string_name_addr);
+ codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_AND, type_comp_addr_1, type_comp_addr_2);
+ codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, type_comp_addr_1);
+
+ codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_EQUAL, p_type_addr, type_string_name_addr);
+ codegen.generator->write_binary_operator(type_comp_addr_2, Variant::OP_EQUAL, literal_type_addr, type_string_addr);
+ codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_AND, type_comp_addr_1, type_comp_addr_2);
+ codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, type_comp_addr_1);
+
+ codegen.generator->pop_temporary(); // Remove type_comp_addr_2 from stack.
+ codegen.generator->pop_temporary(); // Remove type_comp_addr_1 from stack.
+
codegen.generator->write_and_left_operand(type_equality_addr);
// Get literal.
@@ -2096,8 +2118,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
if (EngineDebugger::is_active()) {
String signature;
// Path.
- if (!p_script->get_path().is_empty()) {
- signature += p_script->get_path();
+ if (!p_script->get_script_path().is_empty()) {
+ signature += p_script->get_script_path();
}
// Location.
if (p_func) {
@@ -2368,6 +2390,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
#ifdef TOOLS_ENABLED
if (variable->initializer != nullptr && variable->initializer->is_constant) {
p_script->member_default_values[name] = variable->initializer->reduced_value;
+ GDScriptCompiler::convert_to_initializer_type(p_script->member_default_values[name], variable);
} else {
p_script->member_default_values.erase(name);
}
@@ -2625,6 +2648,20 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
return OK;
}
+void GDScriptCompiler::convert_to_initializer_type(Variant &p_variant, const GDScriptParser::VariableNode *p_node) {
+ // Set p_variant to the value of p_node's initializer, with the type of p_node's variable.
+ GDScriptParser::DataType member_t = p_node->datatype;
+ GDScriptParser::DataType init_t = p_node->initializer->datatype;
+ if (member_t.is_hard_type() && init_t.is_hard_type() &&
+ member_t.kind == GDScriptParser::DataType::BUILTIN && init_t.kind == GDScriptParser::DataType::BUILTIN) {
+ if (Variant::can_convert_strict(init_t.builtin_type, member_t.builtin_type)) {
+ Variant *v = &p_node->initializer->reduced_value;
+ Callable::CallError ce;
+ Variant::construct(member_t.builtin_type, p_variant, const_cast<const Variant **>(&v), 1, ce);
+ }
+ }
+}
+
void GDScriptCompiler::make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
p_script->fully_qualified_name = p_class->fqcn;
p_script->name = p_class->identifier ? p_class->identifier->name : "";
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index cba585e5a5..fc5aa05190 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -140,6 +140,7 @@ class GDScriptCompiler {
bool within_await = false;
public:
+ static void convert_to_initializer_type(Variant &p_variant, const GDScriptParser::VariableNode *p_node);
static void make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state = false);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 6d5936ad2e..79387d1bf6 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1612,7 +1612,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
}
}
- if (!found) {
+ if (!found && base.value.get_type() != Variant::NIL) {
found = _guess_method_return_type_from_base(c, base, call->function_name, r_type);
}
}
@@ -2272,6 +2272,11 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
if (base_type.class_type->has_function(p_method)) {
const GDScriptParser::FunctionNode *method = base_type.class_type->get_member(p_method).function;
if (!is_static || method->is_static) {
+ if (method->get_datatype().is_set() && !method->get_datatype().is_variant()) {
+ r_type.type = method->get_datatype();
+ return true;
+ }
+
int last_return_line = -1;
const GDScriptParser::ExpressionNode *last_returned_value = nullptr;
GDScriptParser::CompletionContext c = p_context;
@@ -2285,10 +2290,6 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
if (_guess_expression_type(c, last_returned_value, r_type)) {
return true;
}
- if (method->get_datatype().is_set() && !method->get_datatype().is_variant()) {
- r_type.type = method->get_datatype();
- return true;
- }
}
}
}
@@ -2624,7 +2625,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
}
- if (p_context.base != nullptr && subscript->is_attribute) {
+ if (subscript->is_attribute) {
bool found_type = _get_subscript_type(p_context, subscript, base_type, &base);
if (!found_type) {
@@ -3288,6 +3289,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
parser.parse(p_code, p_path, true);
GDScriptParser::CompletionContext context = parser.get_completion_context();
+ context.base = p_owner;
// Allows class functions with the names like built-ins to be handled properly.
if (context.type != GDScriptParser::COMPLETION_ATTRIBUTE) {
@@ -3460,7 +3462,9 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
break;
}
GDScriptCompletionIdentifier base;
- if (!_guess_expression_type(context, subscript->base, base)) {
+
+ bool found_type = _get_subscript_type(context, subscript, base.type);
+ if (!found_type && !_guess_expression_type(context, subscript->base, base)) {
break;
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index f2aafe9f0c..103269f0f5 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -642,6 +642,53 @@ void GDScriptParser::parse_program() {
clear_unused_annotations();
}
+GDScriptParser::ClassNode *GDScriptParser::find_class(const String &p_qualified_name) const {
+ String first = p_qualified_name.get_slice("::", 0);
+
+ Vector<String> class_names;
+ GDScriptParser::ClassNode *result = nullptr;
+ // Empty initial name means start at the head.
+ if (first.is_empty() || (head->identifier && first == head->identifier->name)) {
+ class_names = p_qualified_name.split("::");
+ result = head;
+ } else if (p_qualified_name.begins_with(script_path)) {
+ // Script path could have a class path separator("::") in it.
+ class_names = p_qualified_name.trim_prefix(script_path).split("::");
+ result = head;
+ } else if (head->has_member(first)) {
+ class_names = p_qualified_name.split("::");
+ GDScriptParser::ClassNode::Member member = head->get_member(first);
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ result = member.m_class;
+ }
+ }
+
+ // Starts at index 1 because index 0 was handled above.
+ for (int i = 1; result != nullptr && i < class_names.size(); i++) {
+ String current_name = class_names[i];
+ GDScriptParser::ClassNode *next = nullptr;
+ if (result->has_member(current_name)) {
+ GDScriptParser::ClassNode::Member member = result->get_member(current_name);
+ if (member.type == GDScriptParser::ClassNode::Member::CLASS) {
+ next = member.m_class;
+ }
+ }
+ result = next;
+ }
+
+ return result;
+}
+
+bool GDScriptParser::has_class(const GDScriptParser::ClassNode *p_class) const {
+ if (head->fqcn.is_empty() && p_class->fqcn.get_slice("::", 0).is_empty()) {
+ return p_class == head;
+ } else if (p_class->fqcn.begins_with(head->fqcn)) {
+ return find_class(p_class->fqcn.trim_prefix(head->fqcn)) == p_class;
+ }
+
+ return false;
+}
+
GDScriptParser::ClassNode *GDScriptParser::parse_class() {
ClassNode *n_class = alloc_node<ClassNode>();
@@ -2240,7 +2287,7 @@ GDScriptParser::IdentifierNode *GDScriptParser::parse_identifier() {
GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode *p_previous_operand, bool p_can_assign) {
if (!previous.is_identifier()) {
- ERR_FAIL_V_MSG(nullptr, "Parser bug: parsing literal node without literal token.");
+ ERR_FAIL_V_MSG(nullptr, "Parser bug: parsing identifier node without identifier token.");
}
IdentifierNode *identifier = alloc_node<IdentifierNode>();
complete_extents(identifier);
@@ -4042,11 +4089,12 @@ String GDScriptParser::DataType::to_string() const {
}
case ENUM:
return enum_type.operator String() + " (enum)";
+ case RESOLVING:
case UNRESOLVED:
return "<unresolved type>";
}
- ERR_FAIL_V_MSG("<unresolved type", "Kind set outside the enum range.");
+ ERR_FAIL_V_MSG("<unresolved type>", "Kind set outside the enum range.");
}
static Variant::Type _variant_type_to_typed_array_element_type(Variant::Type p_type) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index d092a2a5e9..540ef1c561 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -107,6 +107,7 @@ public:
CLASS, // GDScript.
ENUM, // Enumeration.
VARIANT, // Can be any type.
+ RESOLVING, // Currently resolving.
UNRESOLVED,
};
Kind kind = UNRESOLVED;
@@ -133,9 +134,10 @@ public:
MethodInfo method_info; // For callable/signals.
HashMap<StringName, int64_t> enum_values; // For enums.
- _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
+ _FORCE_INLINE_ bool is_set() const { return kind != RESOLVING && kind != UNRESOLVED; }
+ _FORCE_INLINE_ bool is_resolving() const { return kind == RESOLVING; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
- _FORCE_INLINE_ bool is_variant() const { return kind == VARIANT || kind == UNRESOLVED; }
+ _FORCE_INLINE_ bool is_variant() const { return kind == VARIANT || kind == RESOLVING || kind == UNRESOLVED; }
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
String to_string() const;
@@ -188,6 +190,7 @@ public:
return script_type == p_other.script_type;
case CLASS:
return class_type == p_other.class_type;
+ case RESOLVING:
case UNRESOLVED:
break;
}
@@ -516,6 +519,32 @@ public:
};
EnumNode::Value enum_value;
+ String get_name() const {
+ switch (type) {
+ case UNDEFINED:
+ return "<undefined member>";
+ case CLASS:
+ // All class-type members have an id.
+ return m_class->identifier->name;
+ case CONSTANT:
+ return constant->identifier->name;
+ case FUNCTION:
+ return function->identifier->name;
+ case SIGNAL:
+ return signal->identifier->name;
+ case VARIABLE:
+ return variable->identifier->name;
+ case ENUM:
+ // All enum-type members have an id.
+ return m_enum->identifier->name;
+ case ENUM_VALUE:
+ return enum_value.identifier->name;
+ case GROUP:
+ return annotation->export_info.name;
+ }
+ return "";
+ }
+
String get_type_name() const {
switch (type) {
case UNDEFINED:
@@ -576,31 +605,42 @@ public:
return variable->get_datatype();
case ENUM:
return m_enum->get_datatype();
- case ENUM_VALUE: {
- // Always integer.
- DataType out_type;
- out_type.type_source = DataType::ANNOTATED_EXPLICIT;
- out_type.kind = DataType::BUILTIN;
- out_type.builtin_type = Variant::INT;
- return out_type;
- }
- case SIGNAL: {
- DataType out_type;
- out_type.type_source = DataType::ANNOTATED_EXPLICIT;
- out_type.kind = DataType::BUILTIN;
- out_type.builtin_type = Variant::SIGNAL;
- // TODO: Add parameter info.
- return out_type;
- }
- case GROUP: {
+ case ENUM_VALUE:
+ return enum_value.identifier->get_datatype();
+ case SIGNAL:
+ return signal->get_datatype();
+ case GROUP:
return DataType();
- }
case UNDEFINED:
return DataType();
}
ERR_FAIL_V_MSG(DataType(), "Reaching unhandled type.");
}
+ Node *get_source_node() const {
+ switch (type) {
+ case CLASS:
+ return m_class;
+ case CONSTANT:
+ return constant;
+ case FUNCTION:
+ return function;
+ case VARIABLE:
+ return variable;
+ case ENUM:
+ return m_enum;
+ case ENUM_VALUE:
+ return enum_value.identifier;
+ case SIGNAL:
+ return signal;
+ case GROUP:
+ return annotation;
+ case UNDEFINED:
+ return nullptr;
+ }
+ ERR_FAIL_V_MSG(nullptr, "Reaching unhandled type.");
+ }
+
Member() {}
Member(ClassNode *p_class) {
@@ -1430,6 +1470,8 @@ public:
Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion);
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
+ ClassNode *find_class(const String &p_qualified_name) const;
+ bool has_class(const GDScriptParser::ClassNode *p_class) const;
static Variant::Type get_builtin_type(const StringName &p_type);
CompletionContext get_completion_context() const { return completion_context; }
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index bcbe8b8d2b..27b6792e84 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -294,6 +294,7 @@ struct GDScriptUtilityFunctionsDefinitions {
}
GDScript *p = base.ptr();
+ String path = p->get_script_path();
Vector<StringName> sname;
while (p->_owner) {
@@ -302,7 +303,7 @@ struct GDScriptUtilityFunctionsDefinitions {
}
sname.reverse();
- if (!p->path.is_resource_file()) {
+ if (!path.is_resource_file()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::DICTIONARY;
@@ -317,7 +318,7 @@ struct GDScriptUtilityFunctionsDefinitions {
Dictionary d;
d["@subpath"] = cp;
- d["@path"] = p->get_path();
+ d["@path"] = path;
for (const KeyValue<StringName, GDScript::MemberInfo> &E : base->member_indices) {
if (!d.has(E.key)) {
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index c73ba798aa..fdcc0625d7 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -2227,7 +2227,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
#ifdef DEBUG_ENABLED
gdfs->state.function_name = name;
- gdfs->state.script_path = _script->get_path();
+ gdfs->state.script_path = _script->get_script_path();
#endif
gdfs->state.defarg = defarg;
gdfs->function = this;
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
index 87863baf75..b9a1d301ad 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
@@ -1,2 +1,2 @@
GDTEST_ANALYZER_ERROR
-The member "Vector2" cannot have the same name as a builtin type.
+Class "Vector2" hides a built-in type.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd
new file mode 100644
index 0000000000..d2f6404cd2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.gd
@@ -0,0 +1,8 @@
+func test():
+ print(InnerA.new())
+
+class InnerA extends InnerB:
+ pass
+
+class InnerB extends InnerA:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out
new file mode 100644
index 0000000000..75a94baa17
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_inheritance.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cyclic inheritance.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd
new file mode 100644
index 0000000000..4292534951
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.gd
@@ -0,0 +1,5 @@
+func test():
+ print(c1)
+
+const c1 = c2
+const c2 = c1
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out
new file mode 100644
index 0000000000..e71b3fc56a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_const.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "c1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd
new file mode 100644
index 0000000000..1caef3d366
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.gd
@@ -0,0 +1,5 @@
+func test():
+ print(E1.V)
+
+enum E1 {V = E2.V}
+enum E2 {V = E1.V}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out
new file mode 100644
index 0000000000..1b6569ba3a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "E1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd
new file mode 100644
index 0000000000..237758f340
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.gd
@@ -0,0 +1,5 @@
+func test():
+ print(EV1)
+
+enum {EV1 = EV2}
+enum {EV2 = EV1}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out
new file mode 100644
index 0000000000..233f5fee25
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_enum_value.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "EV1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd
new file mode 100644
index 0000000000..52e0d60389
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.gd
@@ -0,0 +1,6 @@
+func test():
+ print(v)
+
+var v = A.v
+
+const A = preload("cyclic_ref_external_a.notest.gd")
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out
new file mode 100644
index 0000000000..64a6bd417d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "v".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd
new file mode 100644
index 0000000000..9ef1769250
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_external_a.notest.gd
@@ -0,0 +1,3 @@
+const B = preload("cyclic_ref_external.gd")
+
+var v = B.v
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd
new file mode 100644
index 0000000000..b610464c44
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.gd
@@ -0,0 +1,9 @@
+func test():
+ print(f1())
+ print(f2())
+
+static func f1(p := f2()) -> int:
+ return 1
+
+static func f2(p := f1()) -> int:
+ return 2
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out
new file mode 100644
index 0000000000..d3ec4b0692
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_func.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "f1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd
new file mode 100644
index 0000000000..f750715838
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.gd
@@ -0,0 +1,12 @@
+func test():
+ print(v)
+
+var v := InnerA.new().f()
+
+class InnerA:
+ func f(p := InnerB.new().f()) -> int:
+ return 1
+
+class InnerB extends InnerA:
+ func f(p := 1) -> int:
+ return super.f()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out
new file mode 100644
index 0000000000..6bca25b330
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_override.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "f": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd
new file mode 100644
index 0000000000..6913888724
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.gd
@@ -0,0 +1,5 @@
+func test():
+ print(v1)
+
+var v1 := v2
+var v2 := v1
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out
new file mode 100644
index 0000000000..c337882d9c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/cyclic_ref_var.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not resolve member "v1": Cyclic reference.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.gd
new file mode 100644
index 0000000000..4dd2b556ee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.gd
@@ -0,0 +1,9 @@
+# https://github.com/godotengine/godot/issues/62957
+
+func test():
+ var dict = {
+ &"key": "StringName",
+ "key": "String"
+ }
+
+ print("Invalid dictionary: %s" % dict)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.out
new file mode 100644
index 0000000000..189d8a7955
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_string_stringname_equivalent.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Key "key" was already used in this dictionary (at line 5).
diff --git a/modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.gd
new file mode 100644
index 0000000000..eb0003eed8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.gd
@@ -0,0 +1,15 @@
+
+var m_string_array: Array[String] = [&"abc"]
+var m_stringname_array: Array[StringName] = ["abc"]
+
+func test():
+ print(m_string_array)
+ print(m_stringname_array)
+
+ # Converted to String when initialized
+ var string_array: Array[String] = [&"abc"]
+ print(string_array)
+
+ # Converted to StringName when initialized
+ var stringname_array: Array[StringName] = ["abc"]
+ print(stringname_array)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.out b/modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.out
new file mode 100644
index 0000000000..09c199bde1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/array_string_stringname_equivalent.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+["abc"]
+[&"abc"]
+["abc"]
+[&"abc"]
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd
new file mode 100644
index 0000000000..7881a0feb6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd
@@ -0,0 +1,14 @@
+const A: = preload("base_outer_resolution_a.notest.gd")
+const B: = preload("base_outer_resolution_b.notest.gd")
+const C: = preload("base_outer_resolution_c.notest.gd")
+
+const Extend: = preload("base_outer_resolution_extend.notest.gd")
+
+func test() -> void:
+ Extend.test_a(A.new())
+ Extend.test_b(B.new())
+ Extend.InnerClass.test_c(C.new())
+ Extend.InnerClass.InnerInnerClass.test_a_b_c(A.new(), B.new(), C.new())
+ Extend.InnerClass.InnerInnerClass.test_enum(C.TestEnum.HELLO_WORLD)
+ Extend.InnerClass.InnerInnerClass.test_a_prime(A.APrime.new())
+
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.out b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.out
new file mode 100644
index 0000000000..bd27bd31f6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.out
@@ -0,0 +1,7 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_a.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_a.notest.gd
new file mode 100644
index 0000000000..966c8bfc8f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_a.notest.gd
@@ -0,0 +1,2 @@
+class APrime:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_b.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_b.notest.gd
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_b.notest.gd
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_base.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_base.notest.gd
new file mode 100644
index 0000000000..666b147ced
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_base.notest.gd
@@ -0,0 +1,4 @@
+const A: = preload("base_outer_resolution_a.notest.gd")
+
+class InnerClassInBase:
+ const C: = preload("base_outer_resolution_c.notest.gd")
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_c.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_c.notest.gd
new file mode 100644
index 0000000000..814be35314
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_c.notest.gd
@@ -0,0 +1,3 @@
+enum TestEnum {
+ HELLO_WORLD
+}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_extend.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_extend.notest.gd
new file mode 100644
index 0000000000..fbd28779d4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution_extend.notest.gd
@@ -0,0 +1,23 @@
+extends "base_outer_resolution_base.notest.gd"
+
+const B: = preload("base_outer_resolution_b.notest.gd")
+
+static func test_a(a: A) -> void:
+ print(a is A)
+
+static func test_b(b: B) -> void:
+ print(b is B)
+
+class InnerClass extends InnerClassInBase:
+ static func test_c(c: C) -> void:
+ print(c is C)
+
+ class InnerInnerClass:
+ static func test_a_b_c(a: A, b: B, c: C) -> void:
+ print(a is A and b is B and c is C)
+
+ static func test_enum(test_enum: C.TestEnum) -> void:
+ print(test_enum == C.TestEnum.HELLO_WORLD)
+
+ static func test_a_prime(a_prime: A.APrime) -> void:
+ print(a_prime is A.APrime)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd
new file mode 100644
index 0000000000..069e54c528
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.gd
@@ -0,0 +1,50 @@
+func test():
+ print("v1: ", v1)
+ print("v1 is String: ", v1 is String)
+ print("v2: ", v2)
+ print("v2 is bool: ", v2 is bool)
+ print("c1: ", c1)
+ print("c1 is int: ", c1 is int)
+ print("c2: ", c2)
+ print("c2 is int: ", c2 is int)
+ print("E1.V1: ", E1.V1)
+ print("E1.V2: ", E1.V2)
+ print("E2.V: ", E2.V)
+ print("EV1: ", EV1)
+ print("EV2: ", EV2)
+ print("EV3: ", EV3)
+
+var v1 := InnerA.new().fn()
+
+class InnerA extends InnerAB:
+ func fn(p2 := E1.V2) -> String:
+ return "%s, p2=%s" % [super.fn(), p2]
+
+ class InnerAB:
+ func fn(p1 := c1) -> String:
+ return "p1=%s" % p1
+
+var v2 := f()
+
+func f() -> bool:
+ return true
+
+const c1 := E1.V1
+
+enum E1 {
+ V1 = E2.V + 2,
+ V2 = V1 - 1
+}
+
+enum E2 {V = 2}
+
+const c2 := EV2
+
+enum {
+ EV1 = 42,
+ EV2 = EV3 + 1
+}
+
+enum {
+ EV3 = EV1 + 1
+}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order.out b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.out
new file mode 100644
index 0000000000..b1e75d611d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order.out
@@ -0,0 +1,15 @@
+GDTEST_OK
+v1: p1=4, p2=3
+v1 is String: true
+v2: true
+v2 is bool: true
+c1: 4
+c1 is int: true
+c2: 44
+c2 is int: true
+E1.V1: 4
+E1.V2: 3
+E2.V: 2
+EV1: 42
+EV2: 44
+EV3: 43
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd
new file mode 100644
index 0000000000..0b162bdff8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.gd
@@ -0,0 +1,39 @@
+const B = preload("out_of_order_external_a.notest.gd")
+
+func test():
+ print("v1: ", v1)
+ print("v1 is String: ", v1 is String)
+ print("v2: ", v2)
+ print("v2 is bool: ", v2 is bool)
+ print("c1: ", c1)
+ print("c1 is int: ", c1 is int)
+ print("c2: ", c2)
+ print("c2 is int: ", c2 is int)
+ print("E1.V1: ", E1.V1)
+ print("E1.V2: ", E1.V2)
+ print("B.E2.V: ", B.E2.V)
+ print("EV1: ", EV1)
+ print("EV2: ", EV2)
+ print("B.EV3: ", B.EV3)
+
+var v1 := Inner.new().fn()
+
+class Inner extends B.Inner:
+ func fn(p2 := E1.V2) -> String:
+ return "%s, p2=%s" % [super.fn(), p2]
+
+var v2 := B.new().f()
+
+const c1 := E1.V1
+
+enum E1 {
+ V1 = B.E2.V + 2,
+ V2 = V1 - 1
+}
+
+const c2 := EV2
+
+enum {
+ EV1 = 42,
+ EV2 = B.EV3 + 1
+}
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out
new file mode 100644
index 0000000000..437f782fe6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external.out
@@ -0,0 +1,15 @@
+GDTEST_OK
+v1: p1=4, p2=3
+v1 is String: true
+v2: true
+v2 is bool: true
+c1: 4
+c1 is int: true
+c2: 44
+c2 is int: true
+E1.V1: 4
+E1.V2: 3
+B.E2.V: 2
+EV1: 42
+EV2: 44
+B.EV3: 43
diff --git a/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd
new file mode 100644
index 0000000000..d276f72fcf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/out_of_order_external_a.notest.gd
@@ -0,0 +1,12 @@
+const A = preload("out_of_order_external.gd")
+
+class Inner:
+ func fn(p1 := A.c1) -> String:
+ return "p1=%s" % p1
+
+func f(p := A.c1) -> bool:
+ return p is int
+
+enum E2 {V = 2}
+
+enum {EV3 = A.EV1 + 1}
diff --git a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
new file mode 100644
index 0000000000..5303fb04e2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
@@ -0,0 +1,35 @@
+# https://github.com/godotengine/godot/issues/63965
+
+func test():
+ var array_str: Array = []
+ array_str.push_back("godot")
+ print("StringName in Array: ", &"godot" in array_str)
+
+ var array_sname: Array = []
+ array_sname.push_back(&"godot")
+ print("String in Array: ", "godot" in array_sname)
+
+ # Not equal because the values are different types.
+ print("Arrays not equal: ", array_str != array_sname)
+
+ var string_array: Array[String] = []
+ var stringname_array: Array[StringName] = []
+
+ assert(!string_array.push_back(&"abc"))
+ print("Array[String] insert converted: ", typeof(string_array[0]) == TYPE_STRING)
+
+ assert(!stringname_array.push_back("abc"))
+ print("Array[StringName] insert converted: ", typeof(stringname_array[0]) == TYPE_STRING_NAME)
+
+ print("StringName in Array[String]: ", &"abc" in string_array)
+ print("String in Array[StringName]: ", "abc" in stringname_array)
+
+ var packed_string_array: PackedStringArray = []
+ assert(!packed_string_array.push_back("abc"))
+ print("StringName in PackedStringArray: ", &"abc" in packed_string_array)
+
+ assert(!string_array.push_back("abc"))
+ print("StringName finds String in Array: ", string_array.find(&"abc"))
+
+ assert(!stringname_array.push_back(&"abc"))
+ print("String finds StringName in Array: ", stringname_array.find("abc"))
diff --git a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.out b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.out
new file mode 100644
index 0000000000..98ab78e8f1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.out
@@ -0,0 +1,11 @@
+GDTEST_OK
+StringName in Array: true
+String in Array: true
+Arrays not equal: true
+Array[String] insert converted: true
+Array[StringName] insert converted: true
+StringName in Array[String]: true
+String in Array[StringName]: true
+StringName in PackedStringArray: true
+StringName finds String in Array: 0
+String finds StringName in Array: 0
diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd
new file mode 100644
index 0000000000..1f15026f17
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd
@@ -0,0 +1,17 @@
+# https://github.com/godotengine/godot/issues/62957
+
+func test():
+ var string_dict = {}
+ string_dict["abc"] = 42
+ var stringname_dict = {}
+ stringname_dict[&"abc"] = 24
+
+ print("String key is TYPE_STRING: ", typeof(string_dict.keys()[0]) == TYPE_STRING)
+ print("StringName key is TYPE_STRING: ", typeof(stringname_dict.keys()[0]) == TYPE_STRING)
+
+ print("StringName gets String: ", string_dict.get(&"abc"))
+ print("String gets StringName: ", stringname_dict.get("abc"))
+
+ stringname_dict[&"abc"] = 42
+ # They compare equal because StringName keys are converted to String.
+ print("String Dictionary == StringName Dictionary: ", string_dict == stringname_dict)
diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.out b/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.out
new file mode 100644
index 0000000000..ab5b89d55c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+String key is TYPE_STRING: true
+StringName key is TYPE_STRING: true
+StringName gets String: 42
+String gets StringName: 24
+String Dictionary == StringName Dictionary: true
diff --git a/modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.gd
new file mode 100644
index 0000000000..55be021a90
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.gd
@@ -0,0 +1,14 @@
+# https://github.com/godotengine/godot/issues/60145
+
+func test():
+ match "abc":
+ &"abc":
+ print("String matched StringName")
+ _:
+ print("no match")
+
+ match &"abc":
+ "abc":
+ print("StringName matched String")
+ _:
+ print("no match")
diff --git a/modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.out b/modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.out
new file mode 100644
index 0000000000..9d5a18da3d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/match_string_stringname_equivalent.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+String matched StringName
+StringName matched String
diff --git a/modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.gd
new file mode 100644
index 0000000000..f8bd46523e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.gd
@@ -0,0 +1,11 @@
+# https://github.com/godotengine/godot/issues/64171
+
+func test():
+ print("Compare ==: ", "abc" == &"abc")
+ print("Compare ==: ", &"abc" == "abc")
+ print("Compare !=: ", "abc" != &"abc")
+ print("Compare !=: ", &"abc" != "abc")
+
+ print("Concat: ", "abc" + &"def")
+ print("Concat: ", &"abc" + "def")
+ print("Concat: ", &"abc" + &"def")
diff --git a/modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.out b/modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.out
new file mode 100644
index 0000000000..7e9c364b60
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/string_stringname_equivalent.out
@@ -0,0 +1,8 @@
+GDTEST_OK
+Compare ==: true
+Compare ==: true
+Compare !=: false
+Compare !=: false
+Concat: abcdef
+Concat: abcdef
+Concat: abcdef
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index 87d3d9bcb0..6004de32f1 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -42,10 +42,11 @@
</method>
<method name="_export_preflight" qualifiers="virtual">
<return type="int" />
- <param index="0" name="root" type="Node" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="root" type="Node" />
<description>
Part of the export process. This method is run first, before all other parts of the export process.
- The return value is used to determine if this GLTFDocumentExtension class should be used for exporting a given GLTF file. If [constant OK], the export will use this GLTFDocumentExtension class. If not overridden, [constant OK] is returned.
+ The return value is used to determine if this [GLTFDocumentExtension] instance should be used for exporting a given GLTF file. If [constant OK], the export will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned.
</description>
</method>
<method name="_generate_scene_node" qualifiers="virtual">
@@ -99,7 +100,7 @@
<param index="1" name="extensions" type="PackedStringArray" />
<description>
Part of the import process. This method is run first, before all other parts of the import process.
- The return value is used to determine if this GLTFDocumentExtension class should be used for importing a given GLTF file. If [constant OK], the import will use this GLTFDocumentExtension class. If not overridden, [constant OK] is returned.
+ The return value is used to determine if this [GLTFDocumentExtension] instance should be used for importing a given GLTF file. If [constant OK], the import will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned.
</description>
</method>
<method name="_parse_node_extensions" qualifiers="virtual">
@@ -109,7 +110,7 @@
<param index="2" name="extensions" type="Dictionary" />
<description>
Part of the import process. This method is run after [method _get_supported_extensions] and before [method _generate_scene_node].
- Runs when parsing the node extensions of a GLTFNode. This method can be used to process the extension JSON data into a format that can be used by [method _generate_scene_node].
+ Runs when parsing the node extensions of a GLTFNode. This method can be used to process the extension JSON data into a format that can be used by [method _generate_scene_node]. The return value should be a member of the [enum Error] enum.
</description>
</method>
</methods>
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
index 0c0b134bd1..fe63afcc56 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
@@ -33,18 +33,10 @@
#include "editor_scene_exporter_gltf_plugin.h"
#include "../gltf_document.h"
-#include "../gltf_state.h"
-#include "core/config/project_settings.h"
-#include "core/error/error_list.h"
-#include "core/object/object.h"
-#include "core/templates/vector.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/gui/check_box.h"
-#include "scene/main/node.h"
String SceneExporterGLTFPlugin::get_name() const {
return "ConvertGLTF2";
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index 7007ea5d13..4dafa746bc 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -33,7 +33,6 @@
#ifdef TOOLS_ENABLED
#include "../gltf_document.h"
-#include "../gltf_state.h"
#include "core/config/project_settings.h"
#include "editor/editor_file_dialog.h"
@@ -42,8 +41,6 @@
#include "editor/editor_settings.h"
#include "main/main.h"
#include "scene/gui/line_edit.h"
-#include "scene/main/node.h"
-#include "scene/resources/animation.h"
#ifdef WINDOWS_ENABLED
// Code by Pedro Estebanez (https://github.com/godotengine/godot/pull/59766)
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp
index 14f2117413..fb5fb455b8 100644
--- a/modules/gltf/editor/editor_scene_importer_fbx.cpp
+++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp
@@ -33,12 +33,9 @@
#ifdef TOOLS_ENABLED
#include "../gltf_document.h"
-#include "../gltf_state.h"
#include "core/config/project_settings.h"
#include "editor/editor_settings.h"
-#include "scene/main/node.h"
-#include "scene/resources/animation.h"
uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index 3cf49a3046..bd1ba85abf 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -33,9 +33,6 @@
#include "editor_scene_importer_gltf.h"
#include "../gltf_document.h"
-#include "../gltf_state.h"
-
-#include "scene/resources/animation.h"
uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const {
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
@@ -63,7 +60,12 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
if (p_options.has("animation/import")) {
state->set_create_animations(bool(p_options["animation/import"]));
}
- return doc->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]);
+
+ if (p_options.has("animation/trimming")) {
+ return doc->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]);
+ } else {
+ return doc->generate_scene(state, (float)p_options["animation/fps"], false);
+ }
}
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/extensions/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp
index f997fe8f66..630a62ba5c 100644
--- a/modules/gltf/extensions/gltf_document_extension.cpp
+++ b/modules/gltf/extensions/gltf_document_extension.cpp
@@ -40,7 +40,7 @@ void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
GDVIRTUAL_BIND(_import_post, "state", "root");
// Export process.
- GDVIRTUAL_BIND(_export_preflight, "root");
+ GDVIRTUAL_BIND(_export_preflight, "state", "root");
GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node");
GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node");
GDVIRTUAL_BIND(_export_post, "state");
@@ -102,10 +102,10 @@ Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
}
// Export process.
-Error GLTFDocumentExtension::export_preflight(Node *p_root) {
+Error GLTFDocumentExtension::export_preflight(Ref<GLTFState> p_state, Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
int err = OK;
- GDVIRTUAL_CALL(_export_preflight, p_root, err);
+ GDVIRTUAL_CALL(_export_preflight, p_state, p_root, err);
return Error(err);
}
diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h
index 7cc9ca592f..66cb9a3c33 100644
--- a/modules/gltf/extensions/gltf_document_extension.h
+++ b/modules/gltf/extensions/gltf_document_extension.h
@@ -49,7 +49,7 @@ public:
virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error import_post(Ref<GLTFState> p_state, Node *p_node);
// Export process.
- virtual Error export_preflight(Node *p_state);
+ virtual Error export_preflight(Ref<GLTFState> p_state, Node *p_root);
virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node);
virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error export_post(Ref<GLTFState> p_state);
@@ -63,7 +63,7 @@ public:
GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
GDVIRTUAL2R(int, _import_post, Ref<GLTFState>, Node *);
// Export process.
- GDVIRTUAL1R(int, _export_preflight, Node *);
+ GDVIRTUAL2R(int, _export_preflight, Ref<GLTFState>, Node *);
GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL4R(int, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
GDVIRTUAL1R(int, _export_post, Ref<GLTFState>);
diff --git a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
index 49496afb62..cfa498af65 100644
--- a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
+++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
@@ -30,9 +30,7 @@
#include "gltf_document_extension_convert_importer_mesh.h"
-#include "../gltf_state.h"
-
-#include "core/error/error_macros.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/importer_mesh.h"
diff --git a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h
index 00e664e73f..4fbfa0e066 100644
--- a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h
+++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h
@@ -33,10 +33,6 @@
#include "gltf_document_extension.h"
-#include "scene/3d/importer_mesh_instance_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/resources/importer_mesh.h"
-
class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension {
GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension);
diff --git a/modules/gltf/extensions/gltf_light.cpp b/modules/gltf/extensions/gltf_light.cpp
index d00bead61c..0379c62c9d 100644
--- a/modules/gltf/extensions/gltf_light.cpp
+++ b/modules/gltf/extensions/gltf_light.cpp
@@ -30,6 +30,8 @@
#include "gltf_light.h"
+#include "scene/3d/light_3d.h"
+
void GLTFLight::_bind_methods() {
ClassDB::bind_static_method("GLTFLight", D_METHOD("from_node", "light_node"), &GLTFLight::from_node);
ClassDB::bind_method(D_METHOD("to_node"), &GLTFLight::to_node);
diff --git a/modules/gltf/extensions/gltf_light.h b/modules/gltf/extensions/gltf_light.h
index 04980e144c..85284f1d0e 100644
--- a/modules/gltf/extensions/gltf_light.h
+++ b/modules/gltf/extensions/gltf_light.h
@@ -31,9 +31,9 @@
#ifndef GLTF_LIGHT_H
#define GLTF_LIGHT_H
-#include "core/config/engine.h"
#include "core/io/resource.h"
-#include "scene/3d/light_3d.h"
+
+class Light3D;
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual
diff --git a/modules/gltf/extensions/gltf_spec_gloss.cpp b/modules/gltf/extensions/gltf_spec_gloss.cpp
index 83af91bfcc..0645f31e01 100644
--- a/modules/gltf/extensions/gltf_spec_gloss.cpp
+++ b/modules/gltf/extensions/gltf_spec_gloss.cpp
@@ -30,6 +30,8 @@
#include "gltf_spec_gloss.h"
+#include "core/io/image.h"
+
void GLTFSpecGloss::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_diffuse_img"), &GLTFSpecGloss::get_diffuse_img);
ClassDB::bind_method(D_METHOD("set_diffuse_img", "diffuse_img"), &GLTFSpecGloss::set_diffuse_img);
diff --git a/modules/gltf/extensions/gltf_spec_gloss.h b/modules/gltf/extensions/gltf_spec_gloss.h
index 2b4d3ee609..56474acd03 100644
--- a/modules/gltf/extensions/gltf_spec_gloss.h
+++ b/modules/gltf/extensions/gltf_spec_gloss.h
@@ -31,9 +31,10 @@
#ifndef GLTF_SPEC_GLOSS_H
#define GLTF_SPEC_GLOSS_H
-#include "core/io/image.h"
#include "core/io/resource.h"
+class Image;
+
// KHR_materials_pbrSpecularGlossiness is an archived GLTF extension.
// This means that it is deprecated and not recommended for new files.
// However, it is still supported for loading old files.
diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h
index 23bf33869e..7b990e6573 100644
--- a/modules/gltf/gltf_defines.h
+++ b/modules/gltf/gltf_defines.h
@@ -36,9 +36,10 @@
// Godot classes used by GLTF headers.
class BoneAttachment3D;
class CSGShape3D;
-class DirectionalLight3D;
class GridMap;
+class ImporterMeshInstance3D;
class Light3D;
+class MeshInstance3D;
class MultiMeshInstance3D;
class Skeleton3D;
class Skin;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index a3685daf0e..f4db576b0c 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -31,31 +31,23 @@
#include "gltf_document.h"
#include "extensions/gltf_spec_gloss.h"
-#include "gltf_state.h"
#include "core/crypto/crypto_core.h"
-#include "core/error/error_macros.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/file_access_memory.h"
#include "core/io/json.h"
#include "core/io/stream_peer.h"
#include "core/math/disjoint_set.h"
-#include "core/math/vector2.h"
-#include "core/variant/dictionary.h"
-#include "core/variant/typed_array.h"
-#include "core/variant/variant.h"
#include "core/version.h"
#include "drivers/png/png_driver_common.h"
-#include "scene/2d/node_2d.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/animation/animation_player.h"
-#include "scene/resources/importer_mesh.h"
-#include "scene/resources/material.h"
-#include "scene/resources/mesh.h"
-#include "scene/resources/multimesh.h"
+#include "scene/resources/skin.h"
#include "scene/resources/surface_tool.h"
#include "modules/modules_enabled.gen.h" // For csg, gridmap.
@@ -111,147 +103,147 @@ static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) {
return importer_mesh;
}
-Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
- if (!state->buffers.size()) {
- state->buffers.push_back(Vector<uint8_t>());
+Error GLTFDocument::_serialize(Ref<GLTFState> p_state, const String &p_path) {
+ if (!p_state->buffers.size()) {
+ p_state->buffers.push_back(Vector<uint8_t>());
}
/* STEP CONVERT MESH INSTANCES */
- _convert_mesh_instances(state);
+ _convert_mesh_instances(p_state);
/* STEP SERIALIZE CAMERAS */
- Error err = _serialize_cameras(state);
+ Error err = _serialize_cameras(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 3 CREATE SKINS */
- err = _serialize_skins(state);
+ err = _serialize_skins(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE MESHES (we have enough info now) */
- err = _serialize_meshes(state);
+ err = _serialize_meshes(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE TEXTURES */
- err = _serialize_materials(state);
+ err = _serialize_materials(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE TEXTURE SAMPLERS */
- err = _serialize_texture_samplers(state);
+ err = _serialize_texture_samplers(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE ANIMATIONS */
- err = _serialize_animations(state);
+ err = _serialize_animations(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE ACCESSORS */
- err = _encode_accessors(state);
+ err = _encode_accessors(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE IMAGES */
- err = _serialize_images(state, p_path);
+ err = _serialize_images(p_state, p_path);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE TEXTURES */
- err = _serialize_textures(state);
+ err = _serialize_textures(p_state);
if (err != OK) {
return Error::FAILED;
}
- for (GLTFBufferViewIndex i = 0; i < state->buffer_views.size(); i++) {
- state->buffer_views.write[i]->buffer = 0;
+ for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) {
+ p_state->buffer_views.write[i]->buffer = 0;
}
/* STEP SERIALIZE BUFFER VIEWS */
- err = _encode_buffer_views(state);
+ err = _encode_buffer_views(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE NODES */
- err = _serialize_nodes(state);
+ err = _serialize_nodes(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE SCENE */
- err = _serialize_scenes(state);
+ err = _serialize_scenes(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE LIGHTS */
- err = _serialize_lights(state);
+ err = _serialize_lights(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE EXTENSIONS */
- err = _serialize_gltf_extensions(state);
+ err = _serialize_gltf_extensions(p_state);
if (err != OK) {
return Error::FAILED;
}
/* STEP SERIALIZE VERSION */
- err = _serialize_version(state);
+ err = _serialize_version(p_state);
if (err != OK) {
return Error::FAILED;
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- err = ext->export_post(state);
+ err = ext->export_post(p_state);
ERR_FAIL_COND_V(err != OK, err);
}
return OK;
}
-Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> state) const {
- Vector<String> extensions_used = state->extensions_used;
- Vector<String> extensions_required = state->extensions_required;
- if (!state->lights.is_empty()) {
+Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> p_state) const {
+ Vector<String> extensions_used = p_state->extensions_used;
+ Vector<String> extensions_required = p_state->extensions_required;
+ if (!p_state->lights.is_empty()) {
extensions_used.push_back("KHR_lights_punctual");
}
- if (state->use_khr_texture_transform) {
+ if (p_state->use_khr_texture_transform) {
extensions_used.push_back("KHR_texture_transform");
extensions_required.push_back("KHR_texture_transform");
}
if (!extensions_used.is_empty()) {
extensions_used.sort();
- state->json["extensionsUsed"] = extensions_used;
+ p_state->json["extensionsUsed"] = extensions_used;
}
if (!extensions_required.is_empty()) {
extensions_required.sort();
- state->json["extensionsRequired"] = extensions_required;
+ p_state->json["extensionsRequired"] = extensions_required;
}
return OK;
}
-Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) {
+Error GLTFDocument::_serialize_scenes(Ref<GLTFState> p_state) {
Array scenes;
const int loaded_scene = 0;
- state->json["scene"] = loaded_scene;
+ p_state->json["scene"] = loaded_scene;
- if (state->nodes.size()) {
+ if (p_state->nodes.size()) {
Dictionary s;
- if (!state->scene_name.is_empty()) {
- s["name"] = state->scene_name;
+ if (!p_state->scene_name.is_empty()) {
+ s["name"] = p_state->scene_name;
}
Array nodes;
@@ -259,21 +251,21 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) {
s["nodes"] = nodes;
scenes.push_back(s);
}
- state->json["scenes"] = scenes;
+ p_state->json["scenes"] = scenes;
return OK;
}
-Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
+Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> p_state) {
Error err;
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (f.is_null()) {
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (file.is_null()) {
return err;
}
Vector<uint8_t> array;
- array.resize(f->get_length());
- f->get_buffer(array.ptrw(), array.size());
+ array.resize(file->get_length());
+ file->get_buffer(array.ptrw(), array.size());
String text;
text.parse_utf8((const char *)array.ptr(), array.size());
@@ -283,26 +275,26 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
_err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT);
return err;
}
- state->json = json.get_data();
+ p_state->json = json.get_data();
return OK;
}
-Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) {
- ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER);
- ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ);
- uint32_t magic = f->get_32();
+Error GLTFDocument::_parse_glb(Ref<FileAccess> p_file, Ref<GLTFState> p_state) {
+ ERR_FAIL_NULL_V(p_file, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_file->get_position() != 0, ERR_FILE_CANT_READ);
+ uint32_t magic = p_file->get_32();
ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF
- f->get_32(); // version
- f->get_32(); // length
- uint32_t chunk_length = f->get_32();
- uint32_t chunk_type = f->get_32();
+ p_file->get_32(); // version
+ p_file->get_32(); // length
+ uint32_t chunk_length = p_file->get_32();
+ uint32_t chunk_type = p_file->get_32();
ERR_FAIL_COND_V(chunk_type != 0x4E4F534A, ERR_PARSE_ERROR); //JSON
Vector<uint8_t> json_data;
json_data.resize(chunk_length);
- uint32_t len = f->get_buffer(json_data.ptrw(), chunk_length);
+ uint32_t len = p_file->get_buffer(json_data.ptrw(), chunk_length);
ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT);
String text;
@@ -315,21 +307,21 @@ Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) {
return err;
}
- state->json = json.get_data();
+ p_state->json = json.get_data();
//data?
- chunk_length = f->get_32();
- chunk_type = f->get_32();
+ chunk_length = p_file->get_32();
+ chunk_type = p_file->get_32();
- if (f->eof_reached()) {
+ if (p_file->eof_reached()) {
return OK; //all good
}
ERR_FAIL_COND_V(chunk_type != 0x004E4942, ERR_PARSE_ERROR); //BIN
- state->glb_data.resize(chunk_length);
- len = f->get_buffer(state->glb_data.ptrw(), chunk_length);
+ p_state->glb_data.resize(chunk_length);
+ len = p_file->get_buffer(p_state->glb_data.ptrw(), chunk_length);
ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT);
return OK;
@@ -402,11 +394,11 @@ static Vector<real_t> _xform_to_array(const Transform3D p_transform) {
return array;
}
-Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
+Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) {
Array nodes;
- for (int i = 0; i < state->nodes.size(); i++) {
+ for (int i = 0; i < p_state->nodes.size(); i++) {
Dictionary node;
- Ref<GLTFNode> gltf_node = state->nodes[i];
+ Ref<GLTFNode> gltf_node = p_state->nodes[i];
Dictionary extensions;
node["extensions"] = extensions;
if (!gltf_node->get_name().is_empty()) {
@@ -453,18 +445,18 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- ERR_CONTINUE(!state->scene_nodes.find(i));
- Error err = ext->export_node(state, gltf_node, node, state->scene_nodes[i]);
+ ERR_CONTINUE(!p_state->scene_nodes.find(i));
+ Error err = ext->export_node(p_state, gltf_node, node, p_state->scene_nodes[i]);
ERR_CONTINUE(err != OK);
}
nodes.push_back(node);
}
- state->json["nodes"] = nodes;
+ p_state->json["nodes"] = nodes;
return OK;
}
-String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name) {
+String GLTFDocument::_gen_unique_name(Ref<GLTFState> p_state, const String &p_name) {
const String s_name = p_name.validate_node_name();
String u_name;
@@ -475,13 +467,13 @@ String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name
if (index > 1) {
u_name += itos(index);
}
- if (!state->unique_names.has(u_name)) {
+ if (!p_state->unique_names.has(u_name)) {
break;
}
index++;
}
- state->unique_names.insert(u_name);
+ p_state->unique_names.insert(u_name);
return u_name;
}
@@ -497,7 +489,7 @@ String GLTFDocument::_sanitize_animation_name(const String &p_name) {
return anim_name;
}
-String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> state, const String &p_name) {
+String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name) {
const String s_name = _sanitize_animation_name(p_name);
String u_name;
@@ -508,13 +500,13 @@ String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> state, const Stri
if (index > 1) {
u_name += itos(index);
}
- if (!state->unique_animation_names.has(u_name)) {
+ if (!p_state->unique_animation_names.has(u_name)) {
break;
}
index++;
}
- state->unique_animation_names.insert(u_name);
+ p_state->unique_animation_names.insert(u_name);
return u_name;
}
@@ -526,7 +518,7 @@ String GLTFDocument::_sanitize_bone_name(const String &p_name) {
return bone_name;
}
-String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name) {
+String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i, const String &p_name) {
String s_name = _sanitize_bone_name(p_name);
if (s_name.is_empty()) {
s_name = "bone";
@@ -539,23 +531,23 @@ String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkele
if (index > 1) {
u_name += "_" + itos(index);
}
- if (!state->skeletons[skel_i]->unique_names.has(u_name)) {
+ if (!p_state->skeletons[p_skel_i]->unique_names.has(u_name)) {
break;
}
index++;
}
- state->skeletons.write[skel_i]->unique_names.insert(u_name);
+ p_state->skeletons.write[p_skel_i]->unique_names.insert(u_name);
return u_name;
}
-Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) {
- ERR_FAIL_COND_V(!state->json.has("scenes"), ERR_FILE_CORRUPT);
- const Array &scenes = state->json["scenes"];
+Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) {
+ ERR_FAIL_COND_V(!p_state->json.has("scenes"), ERR_FILE_CORRUPT);
+ const Array &scenes = p_state->json["scenes"];
int loaded_scene = 0;
- if (state->json.has("scene")) {
- loaded_scene = state->json["scene"];
+ if (p_state->json.has("scene")) {
+ loaded_scene = p_state->json["scene"];
} else {
WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene.");
}
@@ -566,22 +558,22 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) {
ERR_FAIL_COND_V(!s.has("nodes"), ERR_UNAVAILABLE);
const Array &nodes = s["nodes"];
for (int j = 0; j < nodes.size(); j++) {
- state->root_nodes.push_back(nodes[j]);
+ p_state->root_nodes.push_back(nodes[j]);
}
if (s.has("name") && !String(s["name"]).is_empty() && !((String)s["name"]).begins_with("Scene")) {
- state->scene_name = _gen_unique_name(state, s["name"]);
+ p_state->scene_name = _gen_unique_name(p_state, s["name"]);
} else {
- state->scene_name = _gen_unique_name(state, state->filename);
+ p_state->scene_name = _gen_unique_name(p_state, p_state->filename);
}
}
return OK;
}
-Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
- ERR_FAIL_COND_V(!state->json.has("nodes"), ERR_FILE_CORRUPT);
- const Array &nodes = state->json["nodes"];
+Error GLTFDocument::_parse_nodes(Ref<GLTFState> p_state) {
+ ERR_FAIL_COND_V(!p_state->json.has("nodes"), ERR_FILE_CORRUPT);
+ const Array &nodes = p_state->json["nodes"];
for (int i = 0; i < nodes.size(); i++) {
Ref<GLTFNode> node;
node.instantiate();
@@ -627,8 +619,8 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- Error err = ext->parse_node_extensions(state, node, extensions);
- ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing node extensions for node " + node->get_name() + " in file " + state->filename + ". Continuing.");
+ Error err = ext->parse_node_extensions(p_state, node, extensions);
+ ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing node extensions for node " + node->get_name() + " in file " + p_state->filename + ". Continuing.");
}
}
@@ -639,35 +631,35 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
}
}
- state->nodes.push_back(node);
+ p_state->nodes.push_back(node);
}
// build the hierarchy
- for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
- for (int j = 0; j < state->nodes[node_i]->children.size(); j++) {
- GLTFNodeIndex child_i = state->nodes[node_i]->children[j];
+ for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) {
+ for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) {
+ GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j];
- ERR_FAIL_INDEX_V(child_i, state->nodes.size(), ERR_FILE_CORRUPT);
- ERR_CONTINUE(state->nodes[child_i]->parent != -1); //node already has a parent, wtf.
+ ERR_FAIL_INDEX_V(child_i, p_state->nodes.size(), ERR_FILE_CORRUPT);
+ ERR_CONTINUE(p_state->nodes[child_i]->parent != -1); //node already has a parent, wtf.
- state->nodes.write[child_i]->parent = node_i;
+ p_state->nodes.write[child_i]->parent = node_i;
}
}
- _compute_node_heights(state);
+ _compute_node_heights(p_state);
return OK;
}
-void GLTFDocument::_compute_node_heights(Ref<GLTFState> state) {
- state->root_nodes.clear();
- for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); ++node_i) {
- Ref<GLTFNode> node = state->nodes[node_i];
+void GLTFDocument::_compute_node_heights(Ref<GLTFState> p_state) {
+ p_state->root_nodes.clear();
+ for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) {
+ Ref<GLTFNode> node = p_state->nodes[node_i];
node->height = 0;
GLTFNodeIndex current_i = node_i;
while (current_i >= 0) {
- const GLTFNodeIndex parent_i = state->nodes[current_i]->parent;
+ const GLTFNodeIndex parent_i = p_state->nodes[current_i]->parent;
if (parent_i >= 0) {
++node->height;
}
@@ -675,7 +667,7 @@ void GLTFDocument::_compute_node_heights(Ref<GLTFState> state) {
}
if (node->height == 0) {
- state->root_nodes.push_back(node_i);
+ p_state->root_nodes.push_back(node_i);
}
}
}
@@ -698,86 +690,86 @@ static Vector<uint8_t> _parse_base64_uri(const String &uri) {
return buf;
}
-Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_path) {
- print_verbose("glTF: Total buffers: " + itos(state->buffers.size()));
+Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path) {
+ print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size()));
- if (!state->buffers.size()) {
+ if (!p_state->buffers.size()) {
return OK;
}
Array buffers;
- if (state->buffers.size()) {
- Vector<uint8_t> buffer_data = state->buffers[0];
+ if (p_state->buffers.size()) {
+ Vector<uint8_t> buffer_data = p_state->buffers[0];
Dictionary gltf_buffer;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
}
- for (GLTFBufferIndex i = 1; i < state->buffers.size() - 1; i++) {
- Vector<uint8_t> buffer_data = state->buffers[i];
+ for (GLTFBufferIndex i = 1; i < p_state->buffers.size() - 1; i++) {
+ Vector<uint8_t> buffer_data = p_state->buffers[i];
Dictionary gltf_buffer;
String filename = p_path.get_basename().get_file() + itos(i) + ".bin";
String path = p_path.get_base_dir() + "/" + filename;
Error err;
- Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err);
- if (f.is_null()) {
+ Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (file.is_null()) {
return err;
}
if (buffer_data.size() == 0) {
return OK;
}
- f->create(FileAccess::ACCESS_RESOURCES);
- f->store_buffer(buffer_data.ptr(), buffer_data.size());
+ file->create(FileAccess::ACCESS_RESOURCES);
+ file->store_buffer(buffer_data.ptr(), buffer_data.size());
gltf_buffer["uri"] = filename;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
}
- state->json["buffers"] = buffers;
+ p_state->json["buffers"] = buffers;
return OK;
}
-Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_path) {
- print_verbose("glTF: Total buffers: " + itos(state->buffers.size()));
+Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path) {
+ print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size()));
- if (!state->buffers.size()) {
+ if (!p_state->buffers.size()) {
return OK;
}
Array buffers;
- for (GLTFBufferIndex i = 0; i < state->buffers.size(); i++) {
- Vector<uint8_t> buffer_data = state->buffers[i];
+ for (GLTFBufferIndex i = 0; i < p_state->buffers.size(); i++) {
+ Vector<uint8_t> buffer_data = p_state->buffers[i];
Dictionary gltf_buffer;
String filename = p_path.get_basename().get_file() + itos(i) + ".bin";
String path = p_path.get_base_dir() + "/" + filename;
Error err;
- Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err);
- if (f.is_null()) {
+ Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (file.is_null()) {
return err;
}
if (buffer_data.size() == 0) {
return OK;
}
- f->create(FileAccess::ACCESS_RESOURCES);
- f->store_buffer(buffer_data.ptr(), buffer_data.size());
+ file->create(FileAccess::ACCESS_RESOURCES);
+ file->store_buffer(buffer_data.ptr(), buffer_data.size());
gltf_buffer["uri"] = filename;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
}
- state->json["buffers"] = buffers;
+ p_state->json["buffers"] = buffers;
return OK;
}
-Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_path) {
- if (!state->json.has("buffers")) {
+Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_path) {
+ if (!p_state->json.has("buffers")) {
return OK;
}
- const Array &buffers = state->json["buffers"];
+ const Array &buffers = p_state->json["buffers"];
for (GLTFBufferIndex i = 0; i < buffers.size(); i++) {
- if (i == 0 && state->glb_data.size()) {
- state->buffers.push_back(state->glb_data);
+ if (i == 0 && p_state->glb_data.size()) {
+ p_state->buffers.push_back(p_state->glb_data);
} else {
const Dictionary &buffer = buffers[i];
@@ -803,22 +795,22 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa
ERR_FAIL_COND_V(!buffer.has("byteLength"), ERR_PARSE_ERROR);
int byteLength = buffer["byteLength"];
ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR);
- state->buffers.push_back(buffer_data);
+ p_state->buffers.push_back(buffer_data);
}
}
}
- print_verbose("glTF: Total buffers: " + itos(state->buffers.size()));
+ print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size()));
return OK;
}
-Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) {
+Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> p_state) {
Array buffers;
- for (GLTFBufferViewIndex i = 0; i < state->buffer_views.size(); i++) {
+ for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) {
Dictionary d;
- Ref<GLTFBufferView> buffer_view = state->buffer_views[i];
+ Ref<GLTFBufferView> buffer_view = p_state->buffer_views[i];
d["buffer"] = buffer_view->buffer;
d["byteLength"] = buffer_view->byte_length;
@@ -836,19 +828,19 @@ Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) {
ERR_FAIL_COND_V(!d.has("byteLength"), ERR_INVALID_DATA);
buffers.push_back(d);
}
- print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size()));
+ print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size()));
if (!buffers.size()) {
return OK;
}
- state->json["bufferViews"] = buffers;
+ p_state->json["bufferViews"] = buffers;
return OK;
}
-Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) {
- if (!state->json.has("bufferViews")) {
+Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("bufferViews")) {
return OK;
}
- const Array &buffers = state->json["bufferViews"];
+ const Array &buffers = p_state->json["bufferViews"];
for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) {
const Dictionary &d = buffers[i];
@@ -873,20 +865,20 @@ Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) {
buffer_view->indices = target == GLTFDocument::ELEMENT_ARRAY_BUFFER;
}
- state->buffer_views.push_back(buffer_view);
+ p_state->buffer_views.push_back(buffer_view);
}
- print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size()));
+ print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size()));
return OK;
}
-Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) {
+Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) {
Array accessors;
- for (GLTFAccessorIndex i = 0; i < state->accessors.size(); i++) {
+ for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) {
Dictionary d;
- Ref<GLTFAccessor> accessor = state->accessors[i];
+ Ref<GLTFAccessor> accessor = p_state->accessors[i];
d["componentType"] = accessor->component_type;
d["count"] = accessor->count;
d["type"] = _get_accessor_type_name(accessor->type);
@@ -932,9 +924,9 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) {
if (!accessors.size()) {
return OK;
}
- state->json["accessors"] = accessors;
- ERR_FAIL_COND_V(!state->json.has("accessors"), ERR_FILE_CORRUPT);
- print_verbose("glTF: Total accessors: " + itos(state->accessors.size()));
+ p_state->json["accessors"] = accessors;
+ ERR_FAIL_COND_V(!p_state->json.has("accessors"), ERR_FILE_CORRUPT);
+ print_verbose("glTF: Total accessors: " + itos(p_state->accessors.size()));
return OK;
}
@@ -993,11 +985,11 @@ GLTFType GLTFDocument::_get_type_from_str(const String &p_string) {
ERR_FAIL_V(GLTFType::TYPE_SCALAR);
}
-Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) {
- if (!state->json.has("accessors")) {
+Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("accessors")) {
return OK;
}
- const Array &accessors = state->json["accessors"];
+ const Array &accessors = p_state->json["accessors"];
for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) {
const Dictionary &d = accessors[i];
@@ -1060,10 +1052,10 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) {
}
}
- state->accessors.push_back(accessor);
+ p_state->accessors.push_back(accessor);
}
- print_verbose("glTF: Total accessors: " + itos(state->accessors.size()));
+ print_verbose("glTF: Total accessors: " + itos(p_state->accessors.size()));
return OK;
}
@@ -1108,33 +1100,33 @@ String GLTFDocument::_get_type_name(const GLTFType p_component) {
return names[p_component];
}
-Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, const int count, const GLTFType type, const int component_type, const bool normalized, const int byte_offset, const bool for_vertex, GLTFBufferViewIndex &r_accessor) {
+Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, const int p_count, const GLTFType p_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor) {
const int component_count_for_type[7] = {
1, 2, 3, 4, 4, 9, 16
};
- const int component_count = component_count_for_type[type];
- const int component_size = _get_component_type_size(component_type);
+ const int component_count = component_count_for_type[p_type];
+ const int component_size = _get_component_type_size(p_component_type);
ERR_FAIL_COND_V(component_size == 0, FAILED);
int skip_every = 0;
int skip_bytes = 0;
//special case of alignments, as described in spec
- switch (component_type) {
+ switch (p_component_type) {
case COMPONENT_TYPE_BYTE:
case COMPONENT_TYPE_UNSIGNED_BYTE: {
- if (type == TYPE_MAT2) {
+ if (p_type == TYPE_MAT2) {
skip_every = 2;
skip_bytes = 2;
}
- if (type == TYPE_MAT3) {
+ if (p_type == TYPE_MAT3) {
skip_every = 3;
skip_bytes = 1;
}
} break;
case COMPONENT_TYPE_SHORT:
case COMPONENT_TYPE_UNSIGNED_SHORT: {
- if (type == TYPE_MAT3) {
+ if (p_type == TYPE_MAT3) {
skip_every = 6;
skip_bytes = 4;
}
@@ -1145,39 +1137,39 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
Ref<GLTFBufferView> bv;
bv.instantiate();
- const uint32_t offset = bv->byte_offset = byte_offset;
- Vector<uint8_t> &gltf_buffer = state->buffers.write[0];
+ const uint32_t offset = bv->byte_offset = p_byte_offset;
+ Vector<uint8_t> &gltf_buffer = p_state->buffers.write[0];
- int stride = _get_component_type_size(component_type);
- if (for_vertex && stride % 4) {
+ int stride = _get_component_type_size(p_component_type);
+ if (p_for_vertex && stride % 4) {
stride += 4 - (stride % 4); //according to spec must be multiple of 4
}
//use to debug
- print_verbose("glTF: encoding type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count));
+ print_verbose("glTF: encoding type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count));
- print_verbose("glTF: encoding accessor offset " + itos(byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length));
+ print_verbose("glTF: encoding accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length));
- const int buffer_end = (stride * (count - 1)) + _get_component_type_size(component_type);
+ const int buffer_end = (stride * (p_count - 1)) + _get_component_type_size(p_component_type);
// TODO define bv->byte_stride
bv->byte_offset = gltf_buffer.size();
- switch (component_type) {
+ switch (p_component_type) {
case COMPONENT_TYPE_BYTE: {
Vector<int8_t> buffer;
- buffer.resize(count * component_count);
+ buffer.resize(p_count * component_count);
int32_t dst_i = 0;
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
for (int j = 0; j < component_count; j++) {
if (skip_every && j > 0 && (j % skip_every) == 0) {
dst_i += skip_bytes;
}
- double d = *src;
- if (normalized) {
+ double d = *p_src;
+ if (p_normalized) {
buffer.write[dst_i] = d * 128.0;
} else {
buffer.write[dst_i] = d;
}
- src++;
+ p_src++;
dst_i++;
}
}
@@ -1188,20 +1180,20 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
} break;
case COMPONENT_TYPE_UNSIGNED_BYTE: {
Vector<uint8_t> buffer;
- buffer.resize(count * component_count);
+ buffer.resize(p_count * component_count);
int32_t dst_i = 0;
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
for (int j = 0; j < component_count; j++) {
if (skip_every && j > 0 && (j % skip_every) == 0) {
dst_i += skip_bytes;
}
- double d = *src;
- if (normalized) {
+ double d = *p_src;
+ if (p_normalized) {
buffer.write[dst_i] = d * 255.0;
} else {
buffer.write[dst_i] = d;
}
- src++;
+ p_src++;
dst_i++;
}
}
@@ -1210,20 +1202,20 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
} break;
case COMPONENT_TYPE_SHORT: {
Vector<int16_t> buffer;
- buffer.resize(count * component_count);
+ buffer.resize(p_count * component_count);
int32_t dst_i = 0;
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
for (int j = 0; j < component_count; j++) {
if (skip_every && j > 0 && (j % skip_every) == 0) {
dst_i += skip_bytes;
}
- double d = *src;
- if (normalized) {
+ double d = *p_src;
+ if (p_normalized) {
buffer.write[dst_i] = d * 32768.0;
} else {
buffer.write[dst_i] = d;
}
- src++;
+ p_src++;
dst_i++;
}
}
@@ -1234,20 +1226,20 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
} break;
case COMPONENT_TYPE_UNSIGNED_SHORT: {
Vector<uint16_t> buffer;
- buffer.resize(count * component_count);
+ buffer.resize(p_count * component_count);
int32_t dst_i = 0;
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
for (int j = 0; j < component_count; j++) {
if (skip_every && j > 0 && (j % skip_every) == 0) {
dst_i += skip_bytes;
}
- double d = *src;
- if (normalized) {
+ double d = *p_src;
+ if (p_normalized) {
buffer.write[dst_i] = d * 65535.0;
} else {
buffer.write[dst_i] = d;
}
- src++;
+ p_src++;
dst_i++;
}
}
@@ -1258,16 +1250,16 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
} break;
case COMPONENT_TYPE_INT: {
Vector<int> buffer;
- buffer.resize(count * component_count);
+ buffer.resize(p_count * component_count);
int32_t dst_i = 0;
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
for (int j = 0; j < component_count; j++) {
if (skip_every && j > 0 && (j % skip_every) == 0) {
dst_i += skip_bytes;
}
- double d = *src;
+ double d = *p_src;
buffer.write[dst_i] = d;
- src++;
+ p_src++;
dst_i++;
}
}
@@ -1278,16 +1270,16 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
} break;
case COMPONENT_TYPE_FLOAT: {
Vector<float> buffer;
- buffer.resize(count * component_count);
+ buffer.resize(p_count * component_count);
int32_t dst_i = 0;
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
for (int j = 0; j < component_count; j++) {
if (skip_every && j > 0 && (j % skip_every) == 0) {
dst_i += skip_bytes;
}
- double d = *src;
+ double d = *p_src;
buffer.write[dst_i] = d;
- src++;
+ p_src++;
dst_i++;
}
}
@@ -1300,53 +1292,53 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA);
ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA);
- r_accessor = bv->buffer = state->buffer_views.size();
- state->buffer_views.push_back(bv);
+ r_accessor = bv->buffer = p_state->buffer_views.size();
+ p_state->buffer_views.push_back(bv);
return OK;
}
-Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex) {
- const Ref<GLTFBufferView> bv = state->buffer_views[p_buffer_view];
+Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, const GLTFType p_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex) {
+ const Ref<GLTFBufferView> bv = p_state->buffer_views[p_buffer_view];
- int stride = element_size;
+ int stride = p_element_size;
if (bv->byte_stride != -1) {
stride = bv->byte_stride;
}
- if (for_vertex && stride % 4) {
+ if (p_for_vertex && stride % 4) {
stride += 4 - (stride % 4); //according to spec must be multiple of 4
}
- ERR_FAIL_INDEX_V(bv->buffer, state->buffers.size(), ERR_PARSE_ERROR);
+ ERR_FAIL_INDEX_V(bv->buffer, p_state->buffers.size(), ERR_PARSE_ERROR);
- const uint32_t offset = bv->byte_offset + byte_offset;
- Vector<uint8_t> buffer = state->buffers[bv->buffer]; //copy on write, so no performance hit
+ const uint32_t offset = bv->byte_offset + p_byte_offset;
+ Vector<uint8_t> buffer = p_state->buffers[bv->buffer]; //copy on write, so no performance hit
const uint8_t *bufptr = buffer.ptr();
//use to debug
- print_verbose("glTF: type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count));
- print_verbose("glTF: accessor offset " + itos(byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length));
+ print_verbose("glTF: type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count));
+ print_verbose("glTF: accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length));
- const int buffer_end = (stride * (count - 1)) + element_size;
+ const int buffer_end = (stride * (p_count - 1)) + p_element_size;
ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_PARSE_ERROR);
ERR_FAIL_COND_V((int)(offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR);
//fill everything as doubles
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < p_count; i++) {
const uint8_t *src = &bufptr[offset + i * stride];
- for (int j = 0; j < component_count; j++) {
- if (skip_every && j > 0 && (j % skip_every) == 0) {
- src += skip_bytes;
+ for (int j = 0; j < p_component_count; j++) {
+ if (p_skip_every && j > 0 && (j % p_skip_every) == 0) {
+ src += p_skip_bytes;
}
double d = 0;
- switch (component_type) {
+ switch (p_component_type) {
case COMPONENT_TYPE_BYTE: {
int8_t b = int8_t(*src);
- if (normalized) {
+ if (p_normalized) {
d = (double(b) / 128.0);
} else {
d = double(b);
@@ -1354,7 +1346,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const
} break;
case COMPONENT_TYPE_UNSIGNED_BYTE: {
uint8_t b = *src;
- if (normalized) {
+ if (p_normalized) {
d = (double(b) / 255.0);
} else {
d = double(b);
@@ -1362,7 +1354,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const
} break;
case COMPONENT_TYPE_SHORT: {
int16_t s = *(int16_t *)src;
- if (normalized) {
+ if (p_normalized) {
d = (double(s) / 32768.0);
} else {
d = double(s);
@@ -1370,7 +1362,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const
} break;
case COMPONENT_TYPE_UNSIGNED_SHORT: {
uint16_t s = *(uint16_t *)src;
- if (normalized) {
+ if (p_normalized) {
d = (double(s) / 65535.0);
} else {
d = double(s);
@@ -1384,16 +1376,16 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const
} break;
}
- *dst++ = d;
- src += component_size;
+ *p_dst++ = d;
+ src += p_component_size;
}
}
return OK;
}
-int GLTFDocument::_get_component_type_size(const int component_type) {
- switch (component_type) {
+int GLTFDocument::_get_component_type_size(const int p_component_type) {
+ switch (p_component_type) {
case COMPONENT_TYPE_BYTE:
case COMPONENT_TYPE_UNSIGNED_BYTE:
return 1;
@@ -1413,13 +1405,13 @@ int GLTFDocument::_get_component_type_size(const int component_type) {
return 0;
}
-Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
//spec, for reference:
//https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
- ERR_FAIL_INDEX_V(p_accessor, state->accessors.size(), Vector<double>());
+ ERR_FAIL_INDEX_V(p_accessor, p_state->accessors.size(), Vector<double>());
- const Ref<GLTFAccessor> a = state->accessors[p_accessor];
+ const Ref<GLTFAccessor> a = p_state->accessors[p_accessor];
const int component_count_for_type[7] = {
1, 2, 3, 4, 4, 9, 16
@@ -1464,9 +1456,9 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
double *dst = dst_buffer.ptrw();
if (a->buffer_view >= 0) {
- ERR_FAIL_INDEX_V(a->buffer_view, state->buffer_views.size(), Vector<double>());
+ ERR_FAIL_INDEX_V(a->buffer_view, p_state->buffer_views.size(), Vector<double>());
- const Error err = _decode_buffer_view(state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex);
+ const Error err = _decode_buffer_view(p_state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex);
if (err != OK) {
return Vector<double>();
}
@@ -1483,14 +1475,14 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
indices.resize(a->sparse_count);
const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type);
- Error err = _decode_buffer_view(state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false);
+ Error err = _decode_buffer_view(p_state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false);
if (err != OK) {
return Vector<double>();
}
Vector<double> data;
data.resize(component_count * a->sparse_count);
- err = _decode_buffer_view(state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex);
+ err = _decode_buffer_view(p_state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex);
if (err != OK) {
return Vector<double>();
}
@@ -1507,7 +1499,7 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
return dst_buffer;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, const Vector<int32_t> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, const Vector<int32_t> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1540,7 +1532,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_SCALAR;
const int component_type = GLTFDocument::COMPONENT_TYPE_INT;
@@ -1551,17 +1543,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<int> ret;
if (attribs.size() == 0) {
@@ -1579,8 +1571,8 @@ Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const G
return ret;
}
-Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<float> ret;
if (attribs.size() == 0) {
@@ -1598,7 +1590,7 @@ Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, con
return ret;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, const Vector<Vector2> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> p_state, const Vector<Vector2> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1624,7 +1616,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_VEC2;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -1635,16 +1627,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1673,7 +1665,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state,
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_VEC4;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -1684,31 +1676,31 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state,
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-void GLTFDocument::_calc_accessor_min_max(int i, const int element_count, Vector<double> &type_max, Vector<double> attribs, Vector<double> &type_min) {
- if (i == 0) {
- for (int32_t type_i = 0; type_i < element_count; type_i++) {
- type_max.write[type_i] = attribs[(i * element_count) + type_i];
- type_min.write[type_i] = attribs[(i * element_count) + type_i];
+void GLTFDocument::_calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min) {
+ if (p_i == 0) {
+ for (int32_t type_i = 0; type_i < p_element_count; type_i++) {
+ p_type_max.write[type_i] = p_attribs[(p_i * p_element_count) + type_i];
+ p_type_min.write[type_i] = p_attribs[(p_i * p_element_count) + type_i];
}
}
- for (int32_t type_i = 0; type_i < element_count; type_i++) {
- type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]);
- type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]);
- type_max.write[type_i] = _filter_number(type_max.write[type_i]);
- type_min.write[type_i] = _filter_number(type_min.write[type_i]);
+ for (int32_t type_i = 0; type_i < p_element_count; type_i++) {
+ p_type_max.write[type_i] = MAX(p_attribs[(p_i * p_element_count) + type_i], p_type_max[type_i]);
+ p_type_min.write[type_i] = MIN(p_attribs[(p_i * p_element_count) + type_i], p_type_min[type_i]);
+ p_type_max.write[type_i] = _filter_number(p_type_max.write[type_i]);
+ p_type_min.write[type_i] = _filter_number(p_type_min.write[type_i]);
}
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1738,7 +1730,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_VEC4;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -1749,16 +1741,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1785,7 +1777,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state,
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_VEC4;
const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT;
@@ -1796,16 +1788,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state,
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p_state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1834,7 +1826,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> s
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_VEC4;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -1845,17 +1837,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> s
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Vector2> ret;
if (attribs.size() == 0) {
@@ -1874,7 +1866,7 @@ Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, con
return ret;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, const Vector<real_t> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> p_state, const Vector<real_t> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1899,7 +1891,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state,
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_SCALAR;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -1910,16 +1902,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state,
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, const Vector<Vector3> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1945,7 +1937,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_VEC3;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -1956,16 +1948,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -2013,7 +2005,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state,
Ref<GLTFAccessor> accessor;
accessor.instantiate();
GLTFBufferIndex buffer_view_i;
- int64_t size = state->buffers[0].size();
+ int64_t size = p_state->buffers[0].size();
const GLTFType type = GLTFType::TYPE_MAT4;
const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT;
@@ -2024,17 +2016,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state,
accessor->type = type;
accessor->component_type = component_type;
accessor->byte_offset = 0;
- Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
+ Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i);
if (err != OK) {
return -1;
}
accessor->buffer_view = buffer_view_i;
- state->accessors.push_back(accessor);
- return state->accessors.size() - 1;
+ p_state->accessors.push_back(accessor);
+ return p_state->accessors.size() - 1;
}
-Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Vector3> ret;
if (attribs.size() == 0) {
@@ -2053,15 +2045,15 @@ Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, con
return ret;
}
-Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Color> ret;
if (attribs.size() == 0) {
return ret;
}
- const int type = state->accessors[p_accessor]->type;
+ const int type = p_state->accessors[p_accessor]->type;
ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret);
int vec_len = 3;
if (type == TYPE_VEC4) {
@@ -2079,8 +2071,8 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons
}
return ret;
}
-Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Quaternion> ret;
if (attribs.size() == 0) {
@@ -2098,8 +2090,8 @@ Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> s
}
return ret;
}
-Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Transform2D> ret;
if (attribs.size() == 0) {
@@ -2115,8 +2107,8 @@ Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> sta
return ret;
}
-Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Basis> ret;
if (attribs.size() == 0) {
@@ -2133,8 +2125,8 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons
return ret;
}
-Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
- const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+ const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
Vector<Transform3D> ret;
if (attribs.size() == 0) {
@@ -2152,15 +2144,15 @@ Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state
return ret;
}
-Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
+Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
Array meshes;
- for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) {
+ for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < p_state->meshes.size(); gltf_mesh_i++) {
print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i));
- Ref<ImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
+ Ref<ImporterMesh> import_mesh = p_state->meshes.write[gltf_mesh_i]->get_mesh();
if (import_mesh.is_null()) {
continue;
}
- Array instance_materials = state->meshes.write[gltf_mesh_i]->get_instance_materials();
+ Array instance_materials = p_state->meshes.write[gltf_mesh_i]->get_instance_materials();
Array primitives;
Dictionary gltf_mesh;
Array target_names;
@@ -2213,7 +2205,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
{
Vector<Vector3> a = array[Mesh::ARRAY_VERTEX];
ERR_FAIL_COND_V(!a.size(), ERR_INVALID_DATA);
- attributes["POSITION"] = _encode_accessor_as_vec3(state, a, true);
+ attributes["POSITION"] = _encode_accessor_as_vec3(p_state, a, true);
vertex_num = a.size();
}
{
@@ -2230,7 +2222,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
out.a = a[(i * 4) + 3];
attribs.write[i] = out;
}
- attributes["TANGENT"] = _encode_accessor_as_color(state, attribs, true);
+ attributes["TANGENT"] = _encode_accessor_as_color(p_state, attribs, true);
}
}
{
@@ -2242,19 +2234,19 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
for (int i = 0; i < ret_size; i++) {
attribs.write[i] = Vector3(a[i]).normalized();
}
- attributes["NORMAL"] = _encode_accessor_as_vec3(state, attribs, true);
+ attributes["NORMAL"] = _encode_accessor_as_vec3(p_state, attribs, true);
}
}
{
Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV];
if (a.size()) {
- attributes["TEXCOORD_0"] = _encode_accessor_as_vec2(state, a, true);
+ attributes["TEXCOORD_0"] = _encode_accessor_as_vec2(p_state, a, true);
}
}
{
Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV2];
if (a.size()) {
- attributes["TEXCOORD_1"] = _encode_accessor_as_vec2(state, a, true);
+ attributes["TEXCOORD_1"] = _encode_accessor_as_vec2(p_state, a, true);
}
}
for (int custom_i = 0; custom_i < 3; custom_i++) {
@@ -2283,7 +2275,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
if (!attributes.has(gltf_texcoord_key)) {
Vector<Vector2> empty;
empty.resize(vertex_num);
- attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, empty, true);
+ attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, empty, true);
}
}
@@ -2304,25 +2296,25 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
}
gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
- attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, first_channel, true);
+ attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, first_channel, true);
gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
- attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, second_channel, true);
+ attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, second_channel, true);
}
}
{
Vector<Color> a = array[Mesh::ARRAY_COLOR];
if (a.size()) {
- attributes["COLOR_0"] = _encode_accessor_as_color(state, a, true);
+ attributes["COLOR_0"] = _encode_accessor_as_color(p_state, a, true);
}
}
HashMap<int, int> joint_i_to_bone_i;
- for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
+ for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) {
GLTFSkinIndex skin_i = -1;
- if (state->nodes[node_i]->mesh == gltf_mesh_i) {
- skin_i = state->nodes[node_i]->skin;
+ if (p_state->nodes[node_i]->mesh == gltf_mesh_i) {
+ skin_i = p_state->nodes[node_i]->skin;
}
if (skin_i != -1) {
- joint_i_to_bone_i = state->skins[skin_i]->joint_i_to_bone_i;
+ joint_i_to_bone_i = p_state->skins[skin_i]->joint_i_to_bone_i;
break;
}
}
@@ -2342,7 +2334,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
attribs.write[array_i] = Color(joint_0, joint_1, joint_2, joint_3);
}
}
- attributes["JOINTS_0"] = _encode_accessor_as_joints(state, attribs, true);
+ attributes["JOINTS_0"] = _encode_accessor_as_joints(p_state, attribs, true);
} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
Vector<Color> joints_0;
joints_0.resize(vertex_num);
@@ -2363,8 +2355,8 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
joint_1.a = a[vertex_i * weights_8_count + 7];
joints_1.write[vertex_i] = joint_1;
}
- attributes["JOINTS_0"] = _encode_accessor_as_joints(state, joints_0, true);
- attributes["JOINTS_1"] = _encode_accessor_as_joints(state, joints_1, true);
+ attributes["JOINTS_0"] = _encode_accessor_as_joints(p_state, joints_0, true);
+ attributes["JOINTS_1"] = _encode_accessor_as_joints(p_state, joints_1, true);
}
}
{
@@ -2377,7 +2369,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
for (int i = 0; i < vertex_count; i++) {
attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]);
}
- attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, attribs, true);
+ attributes["WEIGHTS_0"] = _encode_accessor_as_weights(p_state, attribs, true);
} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
Vector<Color> weights_0;
weights_0.resize(vertex_num);
@@ -2398,8 +2390,8 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
weight_1.a = a[vertex_i * weights_8_count + 7];
weights_1.write[vertex_i] = weight_1;
}
- attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, weights_0, true);
- attributes["WEIGHTS_1"] = _encode_accessor_as_weights(state, weights_1, true);
+ attributes["WEIGHTS_0"] = _encode_accessor_as_weights(p_state, weights_0, true);
+ attributes["WEIGHTS_1"] = _encode_accessor_as_weights(p_state, weights_1, true);
}
}
{
@@ -2412,7 +2404,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]);
}
}
- primitive["indices"] = _encode_accessor_as_ints(state, mesh_indices, true);
+ primitive["indices"] = _encode_accessor_as_ints(p_state, mesh_indices, true);
} else {
if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) {
//generate indices because they need to be swapped for CW/CCW
@@ -2431,7 +2423,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
generated_indices.write[k + 2] = k + 1;
}
}
- primitive["indices"] = _encode_accessor_as_ints(state, generated_indices, true);
+ primitive["indices"] = _encode_accessor_as_ints(p_state, generated_indices, true);
}
}
}
@@ -2456,12 +2448,12 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
}
- t["POSITION"] = _encode_accessor_as_vec3(state, varr, true);
+ t["POSITION"] = _encode_accessor_as_vec3(p_state, varr, true);
}
Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL];
if (narr.size()) {
- t["NORMAL"] = _encode_accessor_as_vec3(state, narr, true);
+ t["NORMAL"] = _encode_accessor_as_vec3(p_state, narr, true);
}
Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT];
if (tarr.size()) {
@@ -2474,7 +2466,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
vec3.y = tarr[(i * 4) + 1];
vec3.z = tarr[(i * 4) + 2];
}
- t["TANGENT"] = _encode_accessor_as_vec3(state, attribs, true);
+ t["TANGENT"] = _encode_accessor_as_vec3(p_state, attribs, true);
}
targets.push_back(t);
}
@@ -2489,14 +2481,14 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
mat = import_mesh->get_surface_material(surface_i);
}
if (mat.is_valid()) {
- HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat);
+ HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = p_state->material_cache.find(mat);
if (material_cache_i && material_cache_i->value != -1) {
primitive["material"] = material_cache_i->value;
} else {
- GLTFMaterialIndex mat_i = state->materials.size();
- state->materials.push_back(mat);
+ GLTFMaterialIndex mat_i = p_state->materials.size();
+ p_state->materials.push_back(mat);
primitive["material"] = mat_i;
- state->material_cache.insert(mat, mat_i);
+ p_state->material_cache.insert(mat, mat_i);
}
}
@@ -2513,8 +2505,8 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
weights.resize(target_names.size());
for (int name_i = 0; name_i < target_names.size(); name_i++) {
real_t weight = 0.0;
- if (name_i < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) {
- weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i];
+ if (name_i < p_state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) {
+ weight = p_state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i];
}
weights[name_i] = weight;
}
@@ -2534,18 +2526,18 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
if (!meshes.size()) {
return OK;
}
- state->json["meshes"] = meshes;
+ p_state->json["meshes"] = meshes;
print_verbose("glTF: Total meshes: " + itos(meshes.size()));
return OK;
}
-Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
- if (!state->json.has("meshes")) {
+Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("meshes")) {
return OK;
}
- Array meshes = state->json["meshes"];
+ Array meshes = p_state->json["meshes"];
for (GLTFMeshIndex i = 0; i < meshes.size(); i++) {
print_verbose("glTF: Parsing mesh: " + itos(i));
Dictionary d = meshes[i];
@@ -2564,7 +2556,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (d.has("name") && !String(d["name"]).is_empty()) {
mesh_name = d["name"];
}
- import_mesh->set_name(_gen_unique_name(state, vformat("%s_%s", state->scene_name, mesh_name)));
+ import_mesh->set_name(_gen_unique_name(p_state, vformat("%s_%s", p_state->scene_name, mesh_name)));
for (int j = 0; j < primitives.size(); j++) {
uint32_t flags = 0;
@@ -2600,21 +2592,21 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
int32_t vertex_num = 0;
if (a.has("POSITION")) {
- PackedVector3Array vertices = _decode_accessor_as_vec3(state, a["POSITION"], true);
+ PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true);
array[Mesh::ARRAY_VERTEX] = vertices;
vertex_num = vertices.size();
}
if (a.has("NORMAL")) {
- array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true);
+ array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], true);
}
if (a.has("TANGENT")) {
- array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(state, a["TANGENT"], true);
+ array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT"], true);
}
if (a.has("TEXCOORD_0")) {
- array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(state, a["TEXCOORD_0"], true);
+ array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], true);
}
if (a.has("TEXCOORD_1")) {
- array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(state, a["TEXCOORD_1"], true);
+ array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], true);
}
for (int custom_i = 0; custom_i < 3; custom_i++) {
Vector<float> cur_custom;
@@ -2625,12 +2617,12 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
int num_channels = 0;
if (a.has(gltf_texcoord_key)) {
- texcoord_first = _decode_accessor_as_vec2(state, a[gltf_texcoord_key], true);
+ texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true);
num_channels = 2;
}
gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
if (a.has(gltf_texcoord_key)) {
- texcoord_second = _decode_accessor_as_vec2(state, a[gltf_texcoord_key], true);
+ texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true);
num_channels = 4;
}
if (!num_channels) {
@@ -2671,14 +2663,14 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
}
if (a.has("COLOR_0")) {
- array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true);
+ array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], true);
has_vertex_color = true;
}
if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
- array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
+ array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true);
} else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
- PackedInt32Array joints_0 = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
- PackedInt32Array joints_1 = _decode_accessor_as_ints(state, a["JOINTS_1"], true);
+ PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true);
+ PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1"], true);
ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA);
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
Vector<int> joints;
@@ -2696,7 +2688,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array[Mesh::ARRAY_BONES] = joints;
}
if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
- Vector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
+ Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true);
{ //gltf does not seem to normalize the weights for some reason..
int wc = weights.size();
float *w = weights.ptrw();
@@ -2717,8 +2709,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
array[Mesh::ARRAY_WEIGHTS] = weights;
} else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
- Vector<float> weights_0 = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
- Vector<float> weights_1 = _decode_accessor_as_floats(state, a["WEIGHTS_1"], true);
+ Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true);
+ Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1"], true);
Vector<float> weights;
ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
@@ -2763,7 +2755,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
if (p.has("indices")) {
- Vector<int> indices = _decode_accessor_as_ints(state, p["indices"], false);
+ Vector<int> indices = _decode_accessor_as_ints(p_state, p["indices"], false);
if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
//swap around indices, convert ccw to cw for front face
@@ -2837,7 +2829,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
if (t.has("POSITION")) {
- Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
+ Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION"], true);
const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
const int size = src_varr.size();
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
@@ -2859,7 +2851,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array_copy[Mesh::ARRAY_VERTEX] = varr;
}
if (t.has("NORMAL")) {
- Vector<Vector3> narr = _decode_accessor_as_vec3(state, t["NORMAL"], true);
+ Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], true);
const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
int size = src_narr.size();
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
@@ -2881,7 +2873,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array_copy[Mesh::ARRAY_NORMAL] = narr;
}
if (t.has("TANGENT")) {
- const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true);
+ const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], true);
const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR);
@@ -2939,11 +2931,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
Ref<Material> mat;
String mat_name;
- if (!state->discard_meshes_and_materials) {
+ if (!p_state->discard_meshes_and_materials) {
if (p.has("material")) {
const int material = p["material"];
- ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
- Ref<Material> mat3d = state->materials[material];
+ ERR_FAIL_INDEX_V(material, p_state->materials.size(), ERR_FILE_CORRUPT);
+ Ref<Material> mat3d = p_state->materials[material];
ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
Ref<BaseMaterial3D> base_material = mat3d;
@@ -2985,22 +2977,22 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
mesh->set_blend_weights(blend_weights);
mesh->set_mesh(import_mesh);
- state->meshes.push_back(mesh);
+ p_state->meshes.push_back(mesh);
}
- print_verbose("glTF: Total meshes: " + itos(state->meshes.size()));
+ print_verbose("glTF: Total meshes: " + itos(p_state->meshes.size()));
return OK;
}
-Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path) {
+Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state, const String &p_path) {
Array images;
- for (int i = 0; i < state->images.size(); i++) {
+ for (int i = 0; i < p_state->images.size(); i++) {
Dictionary d;
- ERR_CONTINUE(state->images[i].is_null());
+ ERR_CONTINUE(p_state->images[i].is_null());
- Ref<Image> image = state->images[i]->get_image();
+ Ref<Image> image = p_state->images[i]->get_image();
ERR_CONTINUE(image.is_null());
if (p_path.to_lower().ends_with("glb") || p_path.is_empty()) {
@@ -3011,8 +3003,8 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
const GLTFBufferIndex bi = 0;
bv->buffer = bi;
- bv->byte_offset = state->buffers[bi].size();
- ERR_FAIL_INDEX_V(bi, state->buffers.size(), ERR_PARAMETER_RANGE_ERROR);
+ bv->byte_offset = p_state->buffers[bi].size();
+ ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR);
Vector<uint8_t> buffer;
Ref<ImageTexture> img_tex = image;
@@ -3023,21 +3015,21 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG.");
bv->byte_length = buffer.size();
- state->buffers.write[bi].resize(state->buffers[bi].size() + bv->byte_length);
- memcpy(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
- ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT);
+ p_state->buffers.write[bi].resize(p_state->buffers[bi].size() + bv->byte_length);
+ memcpy(&p_state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
+ ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT);
- state->buffer_views.push_back(bv);
- bvi = state->buffer_views.size() - 1;
+ p_state->buffer_views.push_back(bv);
+ bvi = p_state->buffer_views.size() - 1;
d["bufferView"] = bvi;
d["mimeType"] = "image/png";
} else {
ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
- String img_name = state->images[i]->get_name();
+ String img_name = p_state->images[i]->get_name();
if (img_name.is_empty()) {
img_name = itos(i);
}
- img_name = _gen_unique_name(state, img_name);
+ img_name = _gen_unique_name(p_state, img_name);
img_name = img_name.pad_zeros(3) + ".png";
String texture_dir = "textures";
String path = p_path.get_base_dir();
@@ -3052,25 +3044,25 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
images.push_back(d);
}
- print_verbose("Total images: " + itos(state->images.size()));
+ print_verbose("Total images: " + itos(p_state->images.size()));
if (!images.size()) {
return OK;
}
- state->json["images"] = images;
+ p_state->json["images"] = images;
return OK;
}
-Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_path) {
- ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER);
- if (!state->json.has("images")) {
+Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_path) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ if (!p_state->json.has("images")) {
return OK;
}
// Ref: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#images
- const Array &images = state->json["images"];
+ const Array &images = p_state->json["images"];
for (int i = 0; i < images.size(); i++) {
const Dictionary &d = images[i];
@@ -3108,7 +3100,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
!uri.begins_with("data:image/png;base64") &&
!uri.begins_with("data:image/jpeg;base64")) {
WARN_PRINT(vformat("glTF: Image index '%d' uses an unsupported URI data type: %s. Skipping it.", i, uri));
- state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
continue;
}
data = _parse_base64_uri(uri);
@@ -3133,7 +3125,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
// the material), so we do this only as fallback.
Ref<Texture2D> texture = ResourceLoader::load(uri);
if (texture.is_valid()) {
- state->images.push_back(texture);
+ p_state->images.push_back(texture);
continue;
} else if (mimetype == "image/png" || mimetype == "image/jpeg") {
// Fallback to loading as byte array.
@@ -3142,14 +3134,14 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
data = FileAccess::get_file_as_bytes(uri);
if (data.size() == 0) {
WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s. Skipping it.", i, mimetype, uri));
- state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
continue;
}
data_ptr = data.ptr();
data_size = data.size();
} else {
WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded from URI: %s. Skipping it.", i, uri));
- state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
+ p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
continue;
}
}
@@ -3160,16 +3152,16 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
const GLTFBufferViewIndex bvi = d["bufferView"];
- ERR_FAIL_INDEX_V(bvi, state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR);
+ ERR_FAIL_INDEX_V(bvi, p_state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR);
- Ref<GLTFBufferView> bv = state->buffer_views[bvi];
+ Ref<GLTFBufferView> bv = p_state->buffer_views[bvi];
const GLTFBufferIndex bi = bv->buffer;
- ERR_FAIL_INDEX_V(bi, state->buffers.size(), ERR_PARAMETER_RANGE_ERROR);
+ ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR);
- ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT);
+ ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT);
- data_ptr = &state->buffers[bi][bv->byte_offset];
+ data_ptr = &p_state->buffers[bi][bv->byte_offset];
data_size = bv->byte_length;
}
@@ -3202,26 +3194,26 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
// Now we've done our best, fix your scenes.
if (img.is_null()) {
ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype));
- state->images.push_back(Ref<Texture2D>());
+ p_state->images.push_back(Ref<Texture2D>());
continue;
}
- state->images.push_back(ImageTexture::create_from_image(img));
+ p_state->images.push_back(ImageTexture::create_from_image(img));
}
- print_verbose("glTF: Total images: " + itos(state->images.size()));
+ print_verbose("glTF: Total images: " + itos(p_state->images.size()));
return OK;
}
-Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) {
- if (!state->textures.size()) {
+Error GLTFDocument::_serialize_textures(Ref<GLTFState> p_state) {
+ if (!p_state->textures.size()) {
return OK;
}
Array textures;
- for (int32_t i = 0; i < state->textures.size(); i++) {
+ for (int32_t i = 0; i < p_state->textures.size(); i++) {
Dictionary d;
- Ref<GLTFTexture> t = state->textures[i];
+ Ref<GLTFTexture> t = p_state->textures[i];
ERR_CONTINUE(t->get_src_image() == -1);
d["source"] = t->get_src_image();
@@ -3231,17 +3223,17 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) {
}
textures.push_back(d);
}
- state->json["textures"] = textures;
+ p_state->json["textures"] = textures;
return OK;
}
-Error GLTFDocument::_parse_textures(Ref<GLTFState> state) {
- if (!state->json.has("textures")) {
+Error GLTFDocument::_parse_textures(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("textures")) {
return OK;
}
- const Array &textures = state->json["textures"];
+ const Array &textures = p_state->json["textures"];
for (GLTFTextureIndex i = 0; i < textures.size(); i++) {
const Dictionary &d = textures[i];
@@ -3255,96 +3247,96 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) {
} else {
t->set_sampler(-1);
}
- state->textures.push_back(t);
+ p_state->textures.push_back(t);
}
return OK;
}
-GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) {
+GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> p_state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) {
ERR_FAIL_COND_V(p_texture.is_null(), -1);
Ref<GLTFTexture> gltf_texture;
gltf_texture.instantiate();
ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1);
- GLTFImageIndex gltf_src_image_i = state->images.size();
- state->images.push_back(p_texture);
+ GLTFImageIndex gltf_src_image_i = p_state->images.size();
+ p_state->images.push_back(p_texture);
gltf_texture->set_src_image(gltf_src_image_i);
- gltf_texture->set_sampler(_set_sampler_for_mode(state, p_filter_mode, p_repeats));
- GLTFTextureIndex gltf_texture_i = state->textures.size();
- state->textures.push_back(gltf_texture);
+ gltf_texture->set_sampler(_set_sampler_for_mode(p_state, p_filter_mode, p_repeats));
+ GLTFTextureIndex gltf_texture_i = p_state->textures.size();
+ p_state->textures.push_back(gltf_texture);
return gltf_texture_i;
}
-Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture) {
- ERR_FAIL_INDEX_V(p_texture, state->textures.size(), Ref<Texture2D>());
- const GLTFImageIndex image = state->textures[p_texture]->get_src_image();
+Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) {
+ ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>());
+ const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image();
- ERR_FAIL_INDEX_V(image, state->images.size(), Ref<Texture2D>());
+ ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref<Texture2D>());
- return state->images[image];
+ return p_state->images[image];
}
-GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) {
- for (int i = 0; i < state->texture_samplers.size(); ++i) {
- if (state->texture_samplers[i]->get_filter_mode() == p_filter_mode) {
+GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> p_state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) {
+ for (int i = 0; i < p_state->texture_samplers.size(); ++i) {
+ if (p_state->texture_samplers[i]->get_filter_mode() == p_filter_mode) {
return i;
}
}
- GLTFTextureSamplerIndex gltf_sampler_i = state->texture_samplers.size();
+ GLTFTextureSamplerIndex gltf_sampler_i = p_state->texture_samplers.size();
Ref<GLTFTextureSampler> gltf_sampler;
gltf_sampler.instantiate();
gltf_sampler->set_filter_mode(p_filter_mode);
gltf_sampler->set_wrap_mode(p_repeats);
- state->texture_samplers.push_back(gltf_sampler);
+ p_state->texture_samplers.push_back(gltf_sampler);
return gltf_sampler_i;
}
-Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture) {
- ERR_FAIL_INDEX_V(p_texture, state->textures.size(), Ref<Texture2D>());
- const GLTFTextureSamplerIndex sampler = state->textures[p_texture]->get_sampler();
+Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) {
+ ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>());
+ const GLTFTextureSamplerIndex sampler = p_state->textures[p_texture]->get_sampler();
if (sampler == -1) {
- return state->default_texture_sampler;
+ return p_state->default_texture_sampler;
} else {
- ERR_FAIL_INDEX_V(sampler, state->texture_samplers.size(), Ref<GLTFTextureSampler>());
+ ERR_FAIL_INDEX_V(sampler, p_state->texture_samplers.size(), Ref<GLTFTextureSampler>());
- return state->texture_samplers[sampler];
+ return p_state->texture_samplers[sampler];
}
}
-Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> state) {
- if (!state->texture_samplers.size()) {
+Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> p_state) {
+ if (!p_state->texture_samplers.size()) {
return OK;
}
Array samplers;
- for (int32_t i = 0; i < state->texture_samplers.size(); ++i) {
+ for (int32_t i = 0; i < p_state->texture_samplers.size(); ++i) {
Dictionary d;
- Ref<GLTFTextureSampler> s = state->texture_samplers[i];
+ Ref<GLTFTextureSampler> s = p_state->texture_samplers[i];
d["magFilter"] = s->get_mag_filter();
d["minFilter"] = s->get_min_filter();
d["wrapS"] = s->get_wrap_s();
d["wrapT"] = s->get_wrap_t();
samplers.push_back(d);
}
- state->json["samplers"] = samplers;
+ p_state->json["samplers"] = samplers;
return OK;
}
-Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> state) {
- state->default_texture_sampler.instantiate();
- state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR);
- state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR);
- state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT);
- state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT);
+Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> p_state) {
+ p_state->default_texture_sampler.instantiate();
+ p_state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR);
+ p_state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR);
+ p_state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT);
+ p_state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT);
- if (!state->json.has("samplers")) {
+ if (!p_state->json.has("samplers")) {
return OK;
}
- const Array &samplers = state->json["samplers"];
+ const Array &samplers = p_state->json["samplers"];
for (int i = 0; i < samplers.size(); ++i) {
const Dictionary &d = samplers[i];
@@ -3374,23 +3366,23 @@ Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> state) {
sampler->set_wrap_t(GLTFTextureSampler::WrapMode::DEFAULT);
}
- state->texture_samplers.push_back(sampler);
+ p_state->texture_samplers.push_back(sampler);
}
return OK;
}
-Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
+Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
Array materials;
- for (int32_t i = 0; i < state->materials.size(); i++) {
+ for (int32_t i = 0; i < p_state->materials.size(); i++) {
Dictionary d;
- Ref<Material> material = state->materials[i];
+ Ref<Material> material = p_state->materials[i];
if (material.is_null()) {
materials.push_back(d);
continue;
}
if (!material->get_name().is_empty()) {
- d["name"] = _gen_unique_name(state, material->get_name());
+ d["name"] = _gen_unique_name(p_state, material->get_name());
}
Ref<BaseMaterial3D> base_material = material;
if (base_material.is_valid()) {
@@ -3412,14 +3404,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
albedo_texture->set_name(material->get_name() + "_albedo");
- gltf_texture_index = _set_texture(state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
+ gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
if (gltf_texture_index != -1) {
bct["index"] = gltf_texture_index;
Dictionary extensions = _serialize_texture_transform_uv1(material);
if (!extensions.is_empty()) {
bct["extensions"] = extensions;
- state->use_khr_texture_transform = true;
+ p_state->use_khr_texture_transform = true;
}
mr["baseColorTexture"] = bct;
}
@@ -3543,7 +3535,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex orm_texture_index = -1;
if (has_ao || has_roughness || has_metalness) {
orm_texture->set_name(material->get_name() + "_orm");
- orm_texture_index = _set_texture(state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
+ orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
if (has_ao) {
Dictionary occt;
@@ -3555,7 +3547,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Dictionary extensions = _serialize_texture_transform_uv1(material);
if (!extensions.is_empty()) {
mrt["extensions"] = extensions;
- state->use_khr_texture_transform = true;
+ p_state->use_khr_texture_transform = true;
}
mr["metallicRoughnessTexture"] = mrt;
}
@@ -3598,7 +3590,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex gltf_texture_index = -1;
if (tex.is_valid() && tex->get_image().is_valid()) {
tex->set_name(material->get_name() + "_normal");
- gltf_texture_index = _set_texture(state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
+ gltf_texture_index = _set_texture(p_state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
nt["scale"] = base_material->get_normal_scale();
if (gltf_texture_index != -1) {
@@ -3621,7 +3613,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex gltf_texture_index = -1;
if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) {
emission_texture->set_name(material->get_name() + "_emission");
- gltf_texture_index = _set_texture(state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
+ gltf_texture_index = _set_texture(p_state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
if (gltf_texture_index != -1) {
@@ -3644,18 +3636,18 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (!materials.size()) {
return OK;
}
- state->json["materials"] = materials;
- print_verbose("Total materials: " + itos(state->materials.size()));
+ p_state->json["materials"] = materials;
+ print_verbose("Total materials: " + itos(p_state->materials.size()));
return OK;
}
-Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
- if (!state->json.has("materials")) {
+Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("materials")) {
return OK;
}
- const Array &materials = state->json["materials"];
+ const Array &materials = p_state->json["materials"];
for (GLTFMaterialIndex i = 0; i < materials.size(); i++) {
const Dictionary &d = materials[i];
@@ -3680,12 +3672,12 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (sgm.has("diffuseTexture")) {
const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"];
if (diffuse_texture_dict.has("index")) {
- Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(state, diffuse_texture_dict["index"]);
+ Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(p_state, diffuse_texture_dict["index"]);
if (diffuse_sampler.is_valid()) {
material->set_texture_filter(diffuse_sampler->get_filter_mode());
material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode());
}
- Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]);
+ Ref<Texture2D> diffuse_texture = _get_texture(p_state, diffuse_texture_dict["index"]);
if (diffuse_texture.is_valid()) {
spec_gloss->diffuse_img = diffuse_texture->get_image();
material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture);
@@ -3713,7 +3705,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (sgm.has("specularGlossinessTexture")) {
const Dictionary &spec_gloss_texture = sgm["specularGlossinessTexture"];
if (spec_gloss_texture.has("index")) {
- const Ref<Texture2D> orig_texture = _get_texture(state, spec_gloss_texture["index"]);
+ const Ref<Texture2D> orig_texture = _get_texture(p_state, spec_gloss_texture["index"]);
if (orig_texture.is_valid()) {
spec_gloss->spec_gloss_img = orig_texture->get_image();
}
@@ -3733,10 +3725,10 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (mr.has("baseColorTexture")) {
const Dictionary &bct = mr["baseColorTexture"];
if (bct.has("index")) {
- Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(state, bct["index"]);
+ Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(p_state, bct["index"]);
material->set_texture_filter(bct_sampler->get_filter_mode());
material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode());
- material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(p_state, bct["index"]));
}
if (!mr.has("baseColorFactor")) {
material->set_albedo(Color(1, 1, 1));
@@ -3759,7 +3751,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (mr.has("metallicRoughnessTexture")) {
const Dictionary &bct = mr["metallicRoughnessTexture"];
if (bct.has("index")) {
- const Ref<Texture2D> t = _get_texture(state, bct["index"]);
+ const Ref<Texture2D> t = _get_texture(p_state, bct["index"]);
material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, t);
material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE);
material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, t);
@@ -3777,7 +3769,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (d.has("normalTexture")) {
const Dictionary &bct = d["normalTexture"];
if (bct.has("index")) {
- material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index"]));
material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true);
}
if (bct.has("scale")) {
@@ -3787,7 +3779,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (d.has("occlusionTexture")) {
const Dictionary &bct = d["occlusionTexture"];
if (bct.has("index")) {
- material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index"]));
material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true);
}
@@ -3805,7 +3797,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (d.has("emissiveTexture")) {
const Dictionary &bct = d["emissiveTexture"];
if (bct.has("index")) {
- material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index"]));
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
material->set_emission(Color(0, 0, 0));
}
@@ -3830,30 +3822,30 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
}
}
}
- state->materials.push_back(material);
+ p_state->materials.push_back(material);
}
- print_verbose("Total materials: " + itos(state->materials.size()));
+ print_verbose("Total materials: " + itos(p_state->materials.size()));
return OK;
}
-void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material) {
- if (d.has("extensions")) {
- const Dictionary &extensions = d["extensions"];
+void GLTFDocument::_set_texture_transform_uv1(const Dictionary &p_dict, Ref<BaseMaterial3D> p_material) {
+ if (p_dict.has("extensions")) {
+ const Dictionary &extensions = p_dict["extensions"];
if (extensions.has("KHR_texture_transform")) {
- if (material.is_valid()) {
+ if (p_material.is_valid()) {
const Dictionary &texture_transform = extensions["KHR_texture_transform"];
const Array &offset_arr = texture_transform["offset"];
if (offset_arr.size() == 2) {
const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f);
- material->set_uv1_offset(offset_vector3);
+ p_material->set_uv1_offset(offset_vector3);
}
const Array &scale_arr = texture_transform["scale"];
if (scale_arr.size() == 2) {
const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f);
- material->set_uv1_scale(scale_vector3);
+ p_material->set_uv1_scale(scale_vector3);
}
}
}
@@ -3944,13 +3936,13 @@ void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor
r_base_color = r_base_color.clamp();
}
-GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vector<GLTFNodeIndex> &subset) {
+GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> p_state, const Vector<GLTFNodeIndex> &p_subset) {
int highest = -1;
GLTFNodeIndex best_node = -1;
- for (int i = 0; i < subset.size(); ++i) {
- const GLTFNodeIndex node_i = subset[i];
- const Ref<GLTFNode> node = state->nodes[node_i];
+ for (int i = 0; i < p_subset.size(); ++i) {
+ const GLTFNodeIndex node_i = p_subset[i];
+ const Ref<GLTFNode> node = p_state->nodes[node_i];
if (highest == -1 || node->height < highest) {
highest = node->height;
@@ -3961,38 +3953,38 @@ GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vecto
return best_node;
}
-bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin, const GLTFNodeIndex node_index) {
+bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin, const GLTFNodeIndex p_node_index) {
bool found_joint = false;
- for (int i = 0; i < state->nodes[node_index]->children.size(); ++i) {
- found_joint |= _capture_nodes_in_skin(state, skin, state->nodes[node_index]->children[i]);
+ for (int i = 0; i < p_state->nodes[p_node_index]->children.size(); ++i) {
+ found_joint |= _capture_nodes_in_skin(p_state, p_skin, p_state->nodes[p_node_index]->children[i]);
}
if (found_joint) {
// Mark it if we happen to find another skins joint...
- if (state->nodes[node_index]->joint && skin->joints.find(node_index) < 0) {
- skin->joints.push_back(node_index);
- } else if (skin->non_joints.find(node_index) < 0) {
- skin->non_joints.push_back(node_index);
+ if (p_state->nodes[p_node_index]->joint && p_skin->joints.find(p_node_index) < 0) {
+ p_skin->joints.push_back(p_node_index);
+ } else if (p_skin->non_joints.find(p_node_index) < 0) {
+ p_skin->non_joints.push_back(p_node_index);
}
}
- if (skin->joints.find(node_index) > 0) {
+ if (p_skin->joints.find(p_node_index) > 0) {
return true;
}
return false;
}
-void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
+void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) {
DisjointSet<GLTFNodeIndex> disjoint_set;
- for (int i = 0; i < skin->joints.size(); ++i) {
- const GLTFNodeIndex node_index = skin->joints[i];
- const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ for (int i = 0; i < p_skin->joints.size(); ++i) {
+ const GLTFNodeIndex node_index = p_skin->joints[i];
+ const GLTFNodeIndex parent = p_state->nodes[node_index]->parent;
disjoint_set.insert(node_index);
- if (skin->joints.find(parent) >= 0) {
+ if (p_skin->joints.find(parent) >= 0) {
disjoint_set.create_union(parent, node_index);
}
}
@@ -4010,8 +4002,8 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref
for (int i = 0; i < roots.size(); ++i) {
const GLTFNodeIndex root = roots[i];
- if (maxHeight == -1 || state->nodes[root]->height < maxHeight) {
- maxHeight = state->nodes[root]->height;
+ if (maxHeight == -1 || p_state->nodes[root]->height < maxHeight) {
+ maxHeight = p_state->nodes[root]->height;
}
}
@@ -4019,13 +4011,13 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref
// This sucks, but 99% of all game engines (not just Godot) would have this same issue.
for (int i = 0; i < roots.size(); ++i) {
GLTFNodeIndex current_node = roots[i];
- while (state->nodes[current_node]->height > maxHeight) {
- GLTFNodeIndex parent = state->nodes[current_node]->parent;
+ while (p_state->nodes[current_node]->height > maxHeight) {
+ GLTFNodeIndex parent = p_state->nodes[current_node]->parent;
- if (state->nodes[parent]->joint && skin->joints.find(parent) < 0) {
- skin->joints.push_back(parent);
- } else if (skin->non_joints.find(parent) < 0) {
- skin->non_joints.push_back(parent);
+ if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) {
+ p_skin->joints.push_back(parent);
+ } else if (p_skin->non_joints.find(parent) < 0) {
+ p_skin->non_joints.push_back(parent);
}
current_node = parent;
@@ -4040,21 +4032,21 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref
do {
all_same = true;
- const GLTFNodeIndex first_parent = state->nodes[roots[0]]->parent;
+ const GLTFNodeIndex first_parent = p_state->nodes[roots[0]]->parent;
for (int i = 1; i < roots.size(); ++i) {
- all_same &= (first_parent == state->nodes[roots[i]]->parent);
+ all_same &= (first_parent == p_state->nodes[roots[i]]->parent);
}
if (!all_same) {
for (int i = 0; i < roots.size(); ++i) {
const GLTFNodeIndex current_node = roots[i];
- const GLTFNodeIndex parent = state->nodes[current_node]->parent;
+ const GLTFNodeIndex parent = p_state->nodes[current_node]->parent;
- if (state->nodes[parent]->joint && skin->joints.find(parent) < 0) {
- skin->joints.push_back(parent);
- } else if (skin->non_joints.find(parent) < 0) {
- skin->non_joints.push_back(parent);
+ if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) {
+ p_skin->joints.push_back(parent);
+ } else if (p_skin->non_joints.find(parent) < 0) {
+ p_skin->non_joints.push_back(parent);
}
roots.write[i] = parent;
@@ -4064,19 +4056,19 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref
} while (!all_same);
}
-Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
- _capture_nodes_for_multirooted_skin(state, skin);
+Error GLTFDocument::_expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) {
+ _capture_nodes_for_multirooted_skin(p_state, p_skin);
// Grab all nodes that lay in between skin joints/nodes
DisjointSet<GLTFNodeIndex> disjoint_set;
Vector<GLTFNodeIndex> all_skin_nodes;
- all_skin_nodes.append_array(skin->joints);
- all_skin_nodes.append_array(skin->non_joints);
+ all_skin_nodes.append_array(p_skin->joints);
+ all_skin_nodes.append_array(p_skin->non_joints);
for (int i = 0; i < all_skin_nodes.size(); ++i) {
const GLTFNodeIndex node_index = all_skin_nodes[i];
- const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ const GLTFNodeIndex parent = p_state->nodes[node_index]->parent;
disjoint_set.insert(node_index);
if (all_skin_nodes.find(parent) >= 0) {
@@ -4093,7 +4085,7 @@ Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
Vector<GLTFNodeIndex> set;
disjoint_set.get_members(set, out_owners[i]);
- const GLTFNodeIndex root = _find_highest_node(state, set);
+ const GLTFNodeIndex root = _find_highest_node(p_state, set);
ERR_FAIL_COND_V(root < 0, FAILED);
out_roots.push_back(root);
}
@@ -4101,15 +4093,15 @@ Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
out_roots.sort();
for (int i = 0; i < out_roots.size(); ++i) {
- _capture_nodes_in_skin(state, skin, out_roots[i]);
+ _capture_nodes_in_skin(p_state, p_skin, out_roots[i]);
}
- skin->roots = out_roots;
+ p_skin->roots = out_roots;
return OK;
}
-Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
+Error GLTFDocument::_verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) {
// This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is)
// In case additional interpolating logic is added to the skins, this will help ensure that you
// do not cause it to self implode into a fiery blaze
@@ -4121,12 +4113,12 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
DisjointSet<GLTFNodeIndex> disjoint_set;
Vector<GLTFNodeIndex> all_skin_nodes;
- all_skin_nodes.append_array(skin->joints);
- all_skin_nodes.append_array(skin->non_joints);
+ all_skin_nodes.append_array(p_skin->joints);
+ all_skin_nodes.append_array(p_skin->non_joints);
for (int i = 0; i < all_skin_nodes.size(); ++i) {
const GLTFNodeIndex node_index = all_skin_nodes[i];
- const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ const GLTFNodeIndex parent = p_state->nodes[node_index]->parent;
disjoint_set.insert(node_index);
if (all_skin_nodes.find(parent) >= 0) {
@@ -4143,7 +4135,7 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
Vector<GLTFNodeIndex> set;
disjoint_set.get_members(set, out_owners[i]);
- const GLTFNodeIndex root = _find_highest_node(state, set);
+ const GLTFNodeIndex root = _find_highest_node(p_state, set);
ERR_FAIL_COND_V(root < 0, FAILED);
out_roots.push_back(root);
}
@@ -4153,9 +4145,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
ERR_FAIL_COND_V(out_roots.size() == 0, FAILED);
// Make sure the roots are the exact same (they better be)
- ERR_FAIL_COND_V(out_roots.size() != skin->roots.size(), FAILED);
+ ERR_FAIL_COND_V(out_roots.size() != p_skin->roots.size(), FAILED);
for (int i = 0; i < out_roots.size(); ++i) {
- ERR_FAIL_COND_V(out_roots[i] != skin->roots[i], FAILED);
+ ERR_FAIL_COND_V(out_roots[i] != p_skin->roots[i], FAILED);
}
// Single rooted skin? Perfectly ok!
@@ -4164,9 +4156,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
}
// Make sure all parents of a multi-rooted skin are the SAME
- const GLTFNodeIndex parent = state->nodes[out_roots[0]]->parent;
+ const GLTFNodeIndex parent = p_state->nodes[out_roots[0]]->parent;
for (int i = 1; i < out_roots.size(); ++i) {
- if (state->nodes[out_roots[i]]->parent != parent) {
+ if (p_state->nodes[out_roots[i]]->parent != parent) {
return FAILED;
}
}
@@ -4174,12 +4166,12 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
return OK;
}
-Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
- if (!state->json.has("skins")) {
+Error GLTFDocument::_parse_skins(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("skins")) {
return OK;
}
- const Array &skins = state->json["skins"];
+ const Array &skins = p_state->json["skins"];
// Create the base skins, and mark nodes that are joints
for (int i = 0; i < skins.size(); i++) {
@@ -4193,18 +4185,18 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
const Array &joints = d["joints"];
if (d.has("inverseBindMatrices")) {
- skin->inverse_binds = _decode_accessor_as_xform(state, d["inverseBindMatrices"], false);
+ skin->inverse_binds = _decode_accessor_as_xform(p_state, d["inverseBindMatrices"], false);
ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR);
}
for (int j = 0; j < joints.size(); j++) {
const GLTFNodeIndex node = joints[j];
- ERR_FAIL_INDEX_V(node, state->nodes.size(), ERR_PARSE_ERROR);
+ ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR);
skin->joints.push_back(node);
skin->joints_original.push_back(node);
- state->nodes.write[node]->joint = true;
+ p_state->nodes.write[node]->joint = true;
}
if (d.has("name") && !String(d["name"]).is_empty()) {
@@ -4217,32 +4209,32 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
skin->skin_root = d["skeleton"];
}
- state->skins.push_back(skin);
+ p_state->skins.push_back(skin);
}
- for (GLTFSkinIndex i = 0; i < state->skins.size(); ++i) {
- Ref<GLTFSkin> skin = state->skins.write[i];
+ for (GLTFSkinIndex i = 0; i < p_state->skins.size(); ++i) {
+ Ref<GLTFSkin> skin = p_state->skins.write[i];
// Expand the skin to capture all the extra non-joints that lie in between the actual joints,
// and expand the hierarchy to ensure multi-rooted trees lie on the same height level
- ERR_FAIL_COND_V(_expand_skin(state, skin), ERR_PARSE_ERROR);
- ERR_FAIL_COND_V(_verify_skin(state, skin), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(_expand_skin(p_state, skin), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(_verify_skin(p_state, skin), ERR_PARSE_ERROR);
}
- print_verbose("glTF: Total skins: " + itos(state->skins.size()));
+ print_verbose("glTF: Total skins: " + itos(p_state->skins.size()));
return OK;
}
-Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
+Error GLTFDocument::_determine_skeletons(Ref<GLTFState> p_state) {
// Using a disjoint set, we are going to potentially combine all skins that are actually branches
// of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton.
// This is another unclear issue caused by the current glTF specification.
DisjointSet<GLTFNodeIndex> skeleton_sets;
- for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
- const Ref<GLTFSkin> skin = state->skins[skin_i];
+ for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) {
+ const Ref<GLTFSkin> skin = p_state->skins[skin_i];
Vector<GLTFNodeIndex> all_skin_nodes;
all_skin_nodes.append_array(skin->joints);
@@ -4250,7 +4242,7 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
for (int i = 0; i < all_skin_nodes.size(); ++i) {
const GLTFNodeIndex node_index = all_skin_nodes[i];
- const GLTFNodeIndex parent = state->nodes[node_index]->parent;
+ const GLTFNodeIndex parent = p_state->nodes[node_index]->parent;
skeleton_sets.insert(node_index);
if (all_skin_nodes.find(parent) >= 0) {
@@ -4274,7 +4266,7 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
for (int i = 0; i < groups_representatives.size(); ++i) {
Vector<GLTFNodeIndex> group;
skeleton_sets.get_members(group, groups_representatives[i]);
- highest_group_members.push_back(_find_highest_node(state, group));
+ highest_group_members.push_back(_find_highest_node(p_state, group));
groups.push_back(group);
}
@@ -4286,13 +4278,13 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
const GLTFNodeIndex node_j = highest_group_members[j];
// Even if they are siblings under the root! :)
- if (state->nodes[node_i]->parent == state->nodes[node_j]->parent) {
+ if (p_state->nodes[node_i]->parent == p_state->nodes[node_j]->parent) {
skeleton_sets.create_union(node_i, node_j);
}
}
// Attach any parenting going on together (we need to do this n^2 times)
- const GLTFNodeIndex node_i_parent = state->nodes[node_i]->parent;
+ const GLTFNodeIndex node_i_parent = p_state->nodes[node_i]->parent;
if (node_i_parent >= 0) {
for (int j = 0; j < groups.size() && i != j; ++j) {
const Vector<GLTFNodeIndex> &group = groups[j];
@@ -4319,8 +4311,8 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
Vector<GLTFNodeIndex> skeleton_nodes;
skeleton_sets.get_members(skeleton_nodes, skeleton_owner);
- for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
- Ref<GLTFSkin> skin = state->skins.write[skin_i];
+ for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> skin = p_state->skins.write[skin_i];
// If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton
for (int i = 0; i < skeleton_nodes.size(); ++i) {
@@ -4336,37 +4328,37 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) {
for (int i = 0; i < skeleton_nodes.size(); ++i) {
const GLTFNodeIndex node_i = skeleton_nodes[i];
- if (state->nodes[node_i]->joint) {
+ if (p_state->nodes[node_i]->joint) {
skeleton->joints.push_back(node_i);
} else {
non_joints.push_back(node_i);
}
}
- state->skeletons.push_back(skeleton);
+ p_state->skeletons.push_back(skeleton);
- _reparent_non_joint_skeleton_subtrees(state, state->skeletons.write[skel_i], non_joints);
+ _reparent_non_joint_skeleton_subtrees(p_state, p_state->skeletons.write[skel_i], non_joints);
}
- for (GLTFSkeletonIndex skel_i = 0; skel_i < state->skeletons.size(); ++skel_i) {
- Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i];
+ for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) {
+ Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[skel_i];
for (int i = 0; i < skeleton->joints.size(); ++i) {
const GLTFNodeIndex node_i = skeleton->joints[i];
- Ref<GLTFNode> node = state->nodes[node_i];
+ Ref<GLTFNode> node = p_state->nodes[node_i];
ERR_FAIL_COND_V(!node->joint, ERR_PARSE_ERROR);
ERR_FAIL_COND_V(node->skeleton >= 0, ERR_PARSE_ERROR);
node->skeleton = skel_i;
}
- ERR_FAIL_COND_V(_determine_skeleton_roots(state, skel_i), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(_determine_skeleton_roots(p_state, skel_i), ERR_PARSE_ERROR);
}
return OK;
}
-Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, const Vector<GLTFNodeIndex> &non_joints) {
+Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> p_state, Ref<GLTFSkeleton> p_skeleton, const Vector<GLTFNodeIndex> &p_non_joints) {
DisjointSet<GLTFNodeIndex> subtree_set;
// Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector)
@@ -4377,13 +4369,13 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state,
// skinD depicted here explains this issue:
// https://github.com/KhronosGroup/glTF-Asset-Generator/blob/master/Output/Positive/Animation_Skin
- for (int i = 0; i < non_joints.size(); ++i) {
- const GLTFNodeIndex node_i = non_joints[i];
+ for (int i = 0; i < p_non_joints.size(); ++i) {
+ const GLTFNodeIndex node_i = p_non_joints[i];
subtree_set.insert(node_i);
- const GLTFNodeIndex parent_i = state->nodes[node_i]->parent;
- if (parent_i >= 0 && non_joints.find(parent_i) >= 0 && !state->nodes[parent_i]->joint) {
+ const GLTFNodeIndex parent_i = p_state->nodes[node_i]->parent;
+ if (parent_i >= 0 && p_non_joints.find(parent_i) >= 0 && !p_state->nodes[parent_i]->joint) {
subtree_set.create_union(parent_i, node_i);
}
}
@@ -4400,34 +4392,34 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state,
subtree_set.get_members(subtree_nodes, subtree_root);
for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) {
- Ref<GLTFNode> node = state->nodes[subtree_nodes[subtree_i]];
+ Ref<GLTFNode> node = p_state->nodes[subtree_nodes[subtree_i]];
node->joint = true;
// Add the joint to the skeletons joints
- skeleton->joints.push_back(subtree_nodes[subtree_i]);
+ p_skeleton->joints.push_back(subtree_nodes[subtree_i]);
}
}
return OK;
}
-Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i) {
+Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i) {
DisjointSet<GLTFNodeIndex> disjoint_set;
- for (GLTFNodeIndex i = 0; i < state->nodes.size(); ++i) {
- const Ref<GLTFNode> node = state->nodes[i];
+ for (GLTFNodeIndex i = 0; i < p_state->nodes.size(); ++i) {
+ const Ref<GLTFNode> node = p_state->nodes[i];
- if (node->skeleton != skel_i) {
+ if (node->skeleton != p_skel_i) {
continue;
}
disjoint_set.insert(i);
- if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) {
+ if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == p_skel_i) {
disjoint_set.create_union(node->parent, i);
}
}
- Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i];
+ Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[p_skel_i];
Vector<GLTFNodeIndex> representatives;
disjoint_set.get_representatives(representatives);
@@ -4437,7 +4429,7 @@ Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSk
for (int i = 0; i < representatives.size(); ++i) {
Vector<GLTFNodeIndex> set;
disjoint_set.get_members(set, representatives[i]);
- const GLTFNodeIndex root = _find_highest_node(state, set);
+ const GLTFNodeIndex root = _find_highest_node(p_state, set);
ERR_FAIL_COND_V(root < 0, FAILED);
roots.push_back(root);
}
@@ -4453,9 +4445,9 @@ Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSk
}
// Check that the subtrees have the same parent root
- const GLTFNodeIndex parent = state->nodes[roots[0]]->parent;
+ const GLTFNodeIndex parent = p_state->nodes[roots[0]]->parent;
for (int i = 1; i < roots.size(); ++i) {
- if (state->nodes[roots[i]]->parent != parent) {
+ if (p_state->nodes[roots[i]]->parent != parent) {
return FAILED;
}
}
@@ -4463,16 +4455,16 @@ Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSk
return OK;
}
-Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
- for (GLTFSkeletonIndex skel_i = 0; skel_i < state->skeletons.size(); ++skel_i) {
- Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
+Error GLTFDocument::_create_skeletons(Ref<GLTFState> p_state) {
+ for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) {
+ Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i];
Skeleton3D *skeleton = memnew(Skeleton3D);
gltf_skeleton->godot_skeleton = skeleton;
- state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i;
+ p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i;
// Make a unique name, no gltf node represents this skeleton
- skeleton->set_name(_gen_unique_name(state, "Skeleton3D"));
+ skeleton->set_name(_gen_unique_name(p_state, "Skeleton3D"));
List<GLTFNodeIndex> bones;
@@ -4488,14 +4480,14 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
const GLTFNodeIndex node_i = bones.front()->get();
bones.pop_front();
- Ref<GLTFNode> node = state->nodes[node_i];
+ Ref<GLTFNode> node = p_state->nodes[node_i];
ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED);
{ // Add all child nodes to the stack (deterministically)
Vector<GLTFNodeIndex> child_nodes;
for (int i = 0; i < node->children.size(); ++i) {
const GLTFNodeIndex child_i = node->children[i];
- if (state->nodes[child_i]->skeleton == skel_i) {
+ if (p_state->nodes[child_i]->skeleton == skel_i) {
child_nodes.push_back(child_i);
}
}
@@ -4513,7 +4505,7 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
node->set_name("bone");
}
- node->set_name(_gen_unique_bone_name(state, skel_i, node->get_name()));
+ node->set_name(_gen_unique_bone_name(p_state, skel_i, node->get_name()));
skeleton->add_bone(node->get_name());
skeleton->set_bone_rest(bone_index, node->xform);
@@ -4521,30 +4513,30 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized());
skeleton->set_bone_pose_scale(bone_index, node->scale);
- if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) {
- const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name());
+ if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == skel_i) {
+ const int bone_parent = skeleton->find_bone(p_state->nodes[node->parent]->get_name());
ERR_FAIL_COND_V(bone_parent < 0, FAILED);
- skeleton->set_bone_parent(bone_index, skeleton->find_bone(state->nodes[node->parent]->get_name()));
+ skeleton->set_bone_parent(bone_index, skeleton->find_bone(p_state->nodes[node->parent]->get_name()));
}
- state->scene_nodes.insert(node_i, skeleton);
+ p_state->scene_nodes.insert(node_i, skeleton);
}
}
- ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(state), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(p_state), ERR_PARSE_ERROR);
return OK;
}
-Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> state) {
- for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
- Ref<GLTFSkin> skin = state->skins.write[skin_i];
+Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> p_state) {
+ for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> skin = p_state->skins.write[skin_i];
- Ref<GLTFSkeleton> skeleton = state->skeletons[skin->skeleton];
+ Ref<GLTFSkeleton> skeleton = p_state->skeletons[skin->skeleton];
for (int joint_index = 0; joint_index < skin->joints_original.size(); ++joint_index) {
const GLTFNodeIndex node_i = skin->joints_original[joint_index];
- const Ref<GLTFNode> node = state->nodes[node_i];
+ const Ref<GLTFNode> node = p_state->nodes[node_i];
const int bone_index = skeleton->godot_skeleton->find_bone(node->get_name());
ERR_FAIL_COND_V(bone_index < 0, FAILED);
@@ -4556,28 +4548,28 @@ Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFSt
return OK;
}
-Error GLTFDocument::_serialize_skins(Ref<GLTFState> state) {
- _remove_duplicate_skins(state);
+Error GLTFDocument::_serialize_skins(Ref<GLTFState> p_state) {
+ _remove_duplicate_skins(p_state);
Array json_skins;
- for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) {
- Ref<GLTFSkin> gltf_skin = state->skins[skin_i];
+ for (int skin_i = 0; skin_i < p_state->skins.size(); skin_i++) {
+ Ref<GLTFSkin> gltf_skin = p_state->skins[skin_i];
Dictionary json_skin;
- json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false);
+ json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(p_state, gltf_skin->inverse_binds, false);
json_skin["joints"] = gltf_skin->get_joints();
json_skin["name"] = gltf_skin->get_name();
json_skins.push_back(json_skin);
}
- if (!state->skins.size()) {
+ if (!p_state->skins.size()) {
return OK;
}
- state->json["skins"] = json_skins;
+ p_state->json["skins"] = json_skins;
return OK;
}
-Error GLTFDocument::_create_skins(Ref<GLTFState> state) {
- for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
- Ref<GLTFSkin> gltf_skin = state->skins.write[skin_i];
+Error GLTFDocument::_create_skins(Ref<GLTFState> p_state) {
+ for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) {
+ Ref<GLTFSkin> gltf_skin = p_state->skins.write[skin_i];
Ref<Skin> skin;
skin.instantiate();
@@ -4587,14 +4579,14 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) {
for (int joint_i = 0; joint_i < gltf_skin->joints_original.size(); ++joint_i) {
GLTFNodeIndex node = gltf_skin->joints_original[joint_i];
- String bone_name = state->nodes[node]->get_name();
+ String bone_name = p_state->nodes[node]->get_name();
Transform3D xform;
if (has_ibms) {
xform = gltf_skin->inverse_binds[joint_i];
}
- if (state->use_named_skin_binds) {
+ if (p_state->use_named_skin_binds) {
skin->add_named_bind(bone_name, xform);
} else {
int32_t bone_i = gltf_skin->joint_i_to_bone_i[joint_i];
@@ -4606,35 +4598,35 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) {
}
// Purge the duplicates!
- _remove_duplicate_skins(state);
+ _remove_duplicate_skins(p_state);
// Create unique names now, after removing duplicates
- for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
- Ref<Skin> skin = state->skins.write[skin_i]->godot_skin;
+ for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) {
+ Ref<Skin> skin = p_state->skins.write[skin_i]->godot_skin;
if (skin->get_name().is_empty()) {
// Make a unique name, no gltf node represents this skin
- skin->set_name(_gen_unique_name(state, "Skin"));
+ skin->set_name(_gen_unique_name(p_state, "Skin"));
}
}
return OK;
}
-bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_b) {
- if (skin_a->get_bind_count() != skin_b->get_bind_count()) {
+bool GLTFDocument::_skins_are_same(const Ref<Skin> p_skin_a, const Ref<Skin> p_skin_b) {
+ if (p_skin_a->get_bind_count() != p_skin_b->get_bind_count()) {
return false;
}
- for (int i = 0; i < skin_a->get_bind_count(); ++i) {
- if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) {
+ for (int i = 0; i < p_skin_a->get_bind_count(); ++i) {
+ if (p_skin_a->get_bind_bone(i) != p_skin_b->get_bind_bone(i)) {
return false;
}
- if (skin_a->get_bind_name(i) != skin_b->get_bind_name(i)) {
+ if (p_skin_a->get_bind_name(i) != p_skin_b->get_bind_name(i)) {
return false;
}
- Transform3D a_xform = skin_a->get_bind_pose(i);
- Transform3D b_xform = skin_b->get_bind_pose(i);
+ Transform3D a_xform = p_skin_a->get_bind_pose(i);
+ Transform3D b_xform = p_skin_b->get_bind_pose(i);
if (a_xform != b_xform) {
return false;
@@ -4644,67 +4636,67 @@ bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_
return true;
}
-void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> state) {
- for (int i = 0; i < state->skins.size(); ++i) {
- for (int j = i + 1; j < state->skins.size(); ++j) {
- const Ref<Skin> skin_i = state->skins[i]->godot_skin;
- const Ref<Skin> skin_j = state->skins[j]->godot_skin;
+void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> p_state) {
+ for (int i = 0; i < p_state->skins.size(); ++i) {
+ for (int j = i + 1; j < p_state->skins.size(); ++j) {
+ const Ref<Skin> skin_i = p_state->skins[i]->godot_skin;
+ const Ref<Skin> skin_j = p_state->skins[j]->godot_skin;
if (_skins_are_same(skin_i, skin_j)) {
// replace it and delete the old
- state->skins.write[j]->godot_skin = skin_i;
+ p_state->skins.write[j]->godot_skin = skin_i;
}
}
}
}
-Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) {
- if (state->lights.is_empty()) {
+Error GLTFDocument::_serialize_lights(Ref<GLTFState> p_state) {
+ if (p_state->lights.is_empty()) {
return OK;
}
Array lights;
- for (GLTFLightIndex i = 0; i < state->lights.size(); i++) {
- lights.push_back(state->lights[i]->to_dictionary());
+ for (GLTFLightIndex i = 0; i < p_state->lights.size(); i++) {
+ lights.push_back(p_state->lights[i]->to_dictionary());
}
Dictionary extensions;
- if (state->json.has("extensions")) {
- extensions = state->json["extensions"];
+ if (p_state->json.has("extensions")) {
+ extensions = p_state->json["extensions"];
} else {
- state->json["extensions"] = extensions;
+ p_state->json["extensions"] = extensions;
}
Dictionary lights_punctual;
extensions["KHR_lights_punctual"] = lights_punctual;
lights_punctual["lights"] = lights;
- print_verbose("glTF: Total lights: " + itos(state->lights.size()));
+ print_verbose("glTF: Total lights: " + itos(p_state->lights.size()));
return OK;
}
-Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) {
+Error GLTFDocument::_serialize_cameras(Ref<GLTFState> p_state) {
Array cameras;
- cameras.resize(state->cameras.size());
- for (GLTFCameraIndex i = 0; i < state->cameras.size(); i++) {
- cameras[i] = state->cameras[i]->to_dictionary();
+ cameras.resize(p_state->cameras.size());
+ for (GLTFCameraIndex i = 0; i < p_state->cameras.size(); i++) {
+ cameras[i] = p_state->cameras[i]->to_dictionary();
}
- if (!state->cameras.size()) {
+ if (!p_state->cameras.size()) {
return OK;
}
- state->json["cameras"] = cameras;
+ p_state->json["cameras"] = cameras;
- print_verbose("glTF: Total cameras: " + itos(state->cameras.size()));
+ print_verbose("glTF: Total cameras: " + itos(p_state->cameras.size()));
return OK;
}
-Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
- if (!state->json.has("extensions")) {
+Error GLTFDocument::_parse_lights(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("extensions")) {
return OK;
}
- Dictionary extensions = state->json["extensions"];
+ Dictionary extensions = p_state->json["extensions"];
if (!extensions.has("KHR_lights_punctual")) {
return OK;
}
@@ -4720,26 +4712,26 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
if (light.is_null()) {
return Error::ERR_PARSE_ERROR;
}
- state->lights.push_back(light);
+ p_state->lights.push_back(light);
}
- print_verbose("glTF: Total lights: " + itos(state->lights.size()));
+ print_verbose("glTF: Total lights: " + itos(p_state->lights.size()));
return OK;
}
-Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
- if (!state->json.has("cameras")) {
+Error GLTFDocument::_parse_cameras(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("cameras")) {
return OK;
}
- const Array cameras = state->json["cameras"];
+ const Array cameras = p_state->json["cameras"];
for (GLTFCameraIndex i = 0; i < cameras.size(); i++) {
- state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i]));
+ p_state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i]));
}
- print_verbose("glTF: Total cameras: " + itos(state->cameras.size()));
+ print_verbose("glTF: Total cameras: " + itos(p_state->cameras.size()));
return OK;
}
@@ -4759,24 +4751,24 @@ String GLTFDocument::interpolation_to_string(const GLTFAnimation::Interpolation
return interp;
}
-Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
- if (!state->animation_players.size()) {
+Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) {
+ if (!p_state->animation_players.size()) {
return OK;
}
- for (int32_t player_i = 0; player_i < state->animation_players.size(); player_i++) {
+ for (int32_t player_i = 0; player_i < p_state->animation_players.size(); player_i++) {
List<StringName> animation_names;
- AnimationPlayer *animation_player = state->animation_players[player_i];
+ AnimationPlayer *animation_player = p_state->animation_players[player_i];
animation_player->get_animation_list(&animation_names);
if (animation_names.size()) {
for (int animation_name_i = 0; animation_name_i < animation_names.size(); animation_name_i++) {
- _convert_animation(state, animation_player, animation_names[animation_name_i]);
+ _convert_animation(p_state, animation_player, animation_names[animation_name_i]);
}
}
}
Array animations;
- for (GLTFAnimationIndex animation_i = 0; animation_i < state->animations.size(); animation_i++) {
+ for (GLTFAnimationIndex animation_i = 0; animation_i < p_state->animations.size(); animation_i++) {
Dictionary d;
- Ref<GLTFAnimation> gltf_animation = state->animations[animation_i];
+ Ref<GLTFAnimation> gltf_animation = p_state->animations[animation_i];
if (!gltf_animation->get_tracks().size()) {
continue;
}
@@ -4796,9 +4788,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
s["interpolation"] = interpolation_to_string(track.position_track.interpolation);
Vector<real_t> times = Variant(track.position_track.times);
- s["input"] = _encode_accessor_as_floats(state, times, false);
+ s["input"] = _encode_accessor_as_floats(p_state, times, false);
Vector<Vector3> values = Variant(track.position_track.values);
- s["output"] = _encode_accessor_as_vec3(state, values, false);
+ s["output"] = _encode_accessor_as_vec3(p_state, values, false);
samplers.push_back(s);
@@ -4816,9 +4808,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
s["interpolation"] = interpolation_to_string(track.rotation_track.interpolation);
Vector<real_t> times = Variant(track.rotation_track.times);
- s["input"] = _encode_accessor_as_floats(state, times, false);
+ s["input"] = _encode_accessor_as_floats(p_state, times, false);
Vector<Quaternion> values = track.rotation_track.values;
- s["output"] = _encode_accessor_as_quaternions(state, values, false);
+ s["output"] = _encode_accessor_as_quaternions(p_state, values, false);
samplers.push_back(s);
@@ -4836,9 +4828,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
s["interpolation"] = interpolation_to_string(track.scale_track.interpolation);
Vector<real_t> times = Variant(track.scale_track.times);
- s["input"] = _encode_accessor_as_floats(state, times, false);
+ s["input"] = _encode_accessor_as_floats(p_state, times, false);
Vector<Vector3> values = Variant(track.scale_track.values);
- s["output"] = _encode_accessor_as_vec3(state, values, false);
+ s["output"] = _encode_accessor_as_vec3(p_state, values, false);
samplers.push_back(s);
@@ -4916,8 +4908,8 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
}
s["interpolation"] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation);
- s["input"] = _encode_accessor_as_floats(state, all_track_times, false);
- s["output"] = _encode_accessor_as_floats(state, all_track_values, false);
+ s["input"] = _encode_accessor_as_floats(p_state, all_track_times, false);
+ s["output"] = _encode_accessor_as_floats(p_state, all_track_values, false);
samplers.push_back(s);
@@ -4939,19 +4931,19 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
if (!animations.size()) {
return OK;
}
- state->json["animations"] = animations;
+ p_state->json["animations"] = animations;
- print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'.");
+ print_verbose("glTF: Total animations '" + itos(p_state->animations.size()) + "'.");
return OK;
}
-Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
- if (!state->json.has("animations")) {
+Error GLTFDocument::_parse_animations(Ref<GLTFState> p_state) {
+ if (!p_state->json.has("animations")) {
return OK;
}
- const Array &animations = state->json["animations"];
+ const Array &animations = p_state->json["animations"];
for (GLTFAnimationIndex i = 0; i < animations.size(); i++) {
const Dictionary &d = animations[i];
@@ -4972,7 +4964,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
if (anim_name_lower.begins_with("loop") || anim_name_lower.ends_with("loop") || anim_name_lower.begins_with("cycle") || anim_name_lower.ends_with("cycle")) {
animation->set_loop(true);
}
- animation->set_name(_gen_unique_animation_name(state, anim_name));
+ animation->set_name(_gen_unique_animation_name(p_state, anim_name));
}
for (int j = 0; j < channels.size(); j++) {
@@ -4993,7 +4985,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
GLTFNodeIndex node = t["node"];
String path = t["path"];
- ERR_FAIL_INDEX_V(node, state->nodes.size(), ERR_PARSE_ERROR);
+ ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR);
GLTFAnimation::Track *track = nullptr;
@@ -5028,27 +5020,27 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
}
}
- const Vector<float> times = _decode_accessor_as_floats(state, input, false);
+ const Vector<float> times = _decode_accessor_as_floats(p_state, input, false);
if (path == "translation") {
- const Vector<Vector3> positions = _decode_accessor_as_vec3(state, output, false);
+ const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, output, false);
track->position_track.interpolation = interp;
track->position_track.times = Variant(times); //convert via variant
track->position_track.values = Variant(positions); //convert via variant
} else if (path == "rotation") {
- const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(state, output, false);
+ const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, output, false);
track->rotation_track.interpolation = interp;
track->rotation_track.times = Variant(times); //convert via variant
track->rotation_track.values = rotations;
} else if (path == "scale") {
- const Vector<Vector3> scales = _decode_accessor_as_vec3(state, output, false);
+ const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, output, false);
track->scale_track.interpolation = interp;
track->scale_track.times = Variant(times); //convert via variant
track->scale_track.values = Variant(scales); //convert via variant
} else if (path == "weights") {
- const Vector<float> weights = _decode_accessor_as_floats(state, output, false);
+ const Vector<float> weights = _decode_accessor_as_floats(p_state, output, false);
- ERR_FAIL_INDEX_V(state->nodes[node]->mesh, state->meshes.size(), ERR_PARSE_ERROR);
- Ref<GLTFMesh> mesh = state->meshes[state->nodes[node]->mesh];
+ ERR_FAIL_INDEX_V(p_state->nodes[node]->mesh, p_state->meshes.size(), ERR_PARSE_ERROR);
+ Ref<GLTFMesh> mesh = p_state->meshes[p_state->nodes[node]->mesh];
ERR_CONTINUE(!mesh->get_blend_weights().size());
const int wc = mesh->get_blend_weights().size();
@@ -5076,17 +5068,17 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
}
}
- state->animations.push_back(animation);
+ p_state->animations.push_back(animation);
}
- print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'.");
+ print_verbose("glTF: Total animations '" + itos(p_state->animations.size()) + "'.");
return OK;
}
-void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
- for (int i = 0; i < state->nodes.size(); i++) {
- Ref<GLTFNode> n = state->nodes[i];
+void GLTFDocument::_assign_scene_names(Ref<GLTFState> p_state) {
+ for (int i = 0; i < p_state->nodes.size(); i++) {
+ Ref<GLTFNode> n = p_state->nodes[i];
// Any joints get unique names generated when the skeleton is made, unique to the skeleton
if (n->skeleton >= 0) {
@@ -5095,21 +5087,21 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
if (n->get_name().is_empty()) {
if (n->mesh >= 0) {
- n->set_name(_gen_unique_name(state, "Mesh"));
+ n->set_name(_gen_unique_name(p_state, "Mesh"));
} else if (n->camera >= 0) {
- n->set_name(_gen_unique_name(state, "Camera3D"));
+ n->set_name(_gen_unique_name(p_state, "Camera3D"));
} else {
- n->set_name(_gen_unique_name(state, "Node"));
+ n->set_name(_gen_unique_name(p_state, "Node"));
}
}
- n->set_name(_gen_unique_name(state, n->get_name()));
+ n->set_name(_gen_unique_name(p_state, n->get_name()));
}
}
-BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
- Ref<GLTFNode> bone_node = state->nodes[bone_index];
+BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> p_state, Skeleton3D *p_skeleton, const GLTFNodeIndex p_node_index, const GLTFNodeIndex p_bone_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index];
+ Ref<GLTFNode> bone_node = p_state->nodes[p_bone_index];
BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D);
print_verbose("glTF: Creating bone attachment for: " + gltf_node->get_name());
@@ -5120,7 +5112,7 @@ BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state,
return bone_attachment;
}
-GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInstance3D *p_mesh_instance) {
+GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshInstance3D *p_mesh_instance) {
ERR_FAIL_NULL_V(p_mesh_instance, -1);
if (p_mesh_instance->get_mesh().is_null()) {
return -1;
@@ -5151,20 +5143,20 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst
gltf_mesh->set_instance_materials(instance_materials);
gltf_mesh->set_mesh(current_mesh);
gltf_mesh->set_blend_weights(blend_weights);
- GLTFMeshIndex mesh_i = state->meshes.size();
- state->meshes.push_back(gltf_mesh);
+ GLTFMeshIndex mesh_i = p_state->meshes.size();
+ p_state->meshes.push_back(gltf_mesh);
return mesh_i;
}
-ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
+ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index];
- ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr);
+ ERR_FAIL_INDEX_V(gltf_node->mesh, p_state->meshes.size(), nullptr);
ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
print_verbose("glTF: Creating mesh for: " + gltf_node->get_name());
- Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh];
+ Ref<GLTFMesh> mesh = p_state->meshes.write[gltf_node->mesh];
if (mesh.is_null()) {
return mi;
}
@@ -5176,56 +5168,56 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta
return mi;
}
-Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
+Light3D *GLTFDocument::_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index];
- ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr);
+ ERR_FAIL_INDEX_V(gltf_node->light, p_state->lights.size(), nullptr);
print_verbose("glTF: Creating light for: " + gltf_node->get_name());
- Ref<GLTFLight> l = state->lights[gltf_node->light];
+ Ref<GLTFLight> l = p_state->lights[gltf_node->light];
return l->to_node();
}
-Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
+Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index];
- ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr);
+ ERR_FAIL_INDEX_V(gltf_node->camera, p_state->cameras.size(), nullptr);
print_verbose("glTF: Creating camera for: " + gltf_node->get_name());
- Ref<GLTFCamera> c = state->cameras[gltf_node->camera];
+ Ref<GLTFCamera> c = p_state->cameras[gltf_node->camera];
return c->to_node();
}
-GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_camera) {
+GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> p_state, Camera3D *p_camera) {
print_verbose("glTF: Converting camera: " + p_camera->get_name());
Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera);
- GLTFCameraIndex camera_index = state->cameras.size();
- state->cameras.push_back(c);
+ GLTFCameraIndex camera_index = p_state->cameras.size();
+ p_state->cameras.push_back(c);
return camera_index;
}
-GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_light) {
+GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> p_state, Light3D *p_light) {
print_verbose("glTF: Converting light: " + p_light->get_name());
Ref<GLTFLight> l = GLTFLight::from_node(p_light);
- GLTFLightIndex light_index = state->lights.size();
- state->lights.push_back(l);
+ GLTFLightIndex light_index = p_state->lights.size();
+ p_state->lights.push_back(l);
return light_index;
}
-void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) {
+void GLTFDocument::_convert_spatial(Ref<GLTFState> p_state, Node3D *p_spatial, Ref<GLTFNode> p_node) {
Transform3D xform = p_spatial->get_transform();
p_node->scale = xform.basis.get_scale();
p_node->rotation = xform.basis.get_rotation_quaternion();
p_node->position = xform.origin;
}
-Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
+Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index];
Node3D *spatial = memnew(Node3D);
print_verbose("glTF: Converting spatial: " + gltf_node->get_name());
@@ -5233,7 +5225,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeInde
return spatial;
}
-void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
+void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
bool retflag = true;
_check_visibility(p_current, retflag);
if (retflag) {
@@ -5241,68 +5233,68 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co
}
Ref<GLTFNode> gltf_node;
gltf_node.instantiate();
- gltf_node->set_name(_gen_unique_name(state, p_current->get_name()));
+ gltf_node->set_name(_gen_unique_name(p_state, p_current->get_name()));
if (cast_to<Node3D>(p_current)) {
Node3D *spatial = cast_to<Node3D>(p_current);
- _convert_spatial(state, spatial, gltf_node);
+ _convert_spatial(p_state, spatial, gltf_node);
}
if (cast_to<MeshInstance3D>(p_current)) {
MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current);
- _convert_mesh_instance_to_gltf(mi, state, gltf_node);
+ _convert_mesh_instance_to_gltf(mi, p_state, gltf_node);
} else if (cast_to<BoneAttachment3D>(p_current)) {
BoneAttachment3D *bone = cast_to<BoneAttachment3D>(p_current);
- _convert_bone_attachment_to_gltf(bone, state, p_gltf_parent, p_gltf_root, gltf_node);
+ _convert_bone_attachment_to_gltf(bone, p_state, p_gltf_parent, p_gltf_root, gltf_node);
return;
} else if (cast_to<Skeleton3D>(p_current)) {
Skeleton3D *skel = cast_to<Skeleton3D>(p_current);
- _convert_skeleton_to_gltf(skel, state, p_gltf_parent, p_gltf_root, gltf_node);
+ _convert_skeleton_to_gltf(skel, p_state, p_gltf_parent, p_gltf_root, gltf_node);
// We ignore the Godot Engine node that is the skeleton.
return;
} else if (cast_to<MultiMeshInstance3D>(p_current)) {
MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current);
- _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state);
+ _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, p_state);
#ifdef MODULE_CSG_ENABLED
} else if (cast_to<CSGShape3D>(p_current)) {
CSGShape3D *shape = cast_to<CSGShape3D>(p_current);
if (shape->get_parent() && shape->is_root_shape()) {
- _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, state);
+ _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, p_state);
}
#endif // MODULE_CSG_ENABLED
#ifdef MODULE_GRIDMAP_ENABLED
} else if (cast_to<GridMap>(p_current)) {
GridMap *gridmap = Object::cast_to<GridMap>(p_current);
- _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, state);
+ _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, p_state);
#endif // MODULE_GRIDMAP_ENABLED
} else if (cast_to<Camera3D>(p_current)) {
Camera3D *camera = Object::cast_to<Camera3D>(p_current);
- _convert_camera_to_gltf(camera, state, gltf_node);
+ _convert_camera_to_gltf(camera, p_state, gltf_node);
} else if (cast_to<Light3D>(p_current)) {
Light3D *light = Object::cast_to<Light3D>(p_current);
- _convert_light_to_gltf(light, state, gltf_node);
+ _convert_light_to_gltf(light, p_state, gltf_node);
} else if (cast_to<AnimationPlayer>(p_current)) {
AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current);
- _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current);
+ _convert_animation_player_to_gltf(animation_player, p_state, p_gltf_parent, p_gltf_root, gltf_node, p_current);
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- ext->convert_scene_node(state, gltf_node, p_current);
+ ext->convert_scene_node(p_state, gltf_node, p_current);
}
- GLTFNodeIndex current_node_i = state->nodes.size();
+ GLTFNodeIndex current_node_i = p_state->nodes.size();
GLTFNodeIndex gltf_root = p_gltf_root;
if (gltf_root == -1) {
gltf_root = current_node_i;
Array scenes;
scenes.push_back(gltf_root);
- state->json["scene"] = scenes;
+ p_state->json["scene"] = scenes;
}
- _create_gltf_node(state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node);
+ _create_gltf_node(p_state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node);
for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) {
- _convert_scene_node(state, p_current->get_child(node_i), current_node_i, gltf_root);
+ _convert_scene_node(p_state, p_current->get_child(node_i), current_node_i, gltf_root);
}
}
#ifdef MODULE_CSG_ENABLED
-void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) {
CSGShape3D *csg = p_current;
csg->call("_update_shape");
Array meshes = csg->get_meshes();
@@ -5334,34 +5326,34 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
gltf_mesh->set_mesh(mesh);
- GLTFMeshIndex mesh_i = state->meshes.size();
- state->meshes.push_back(gltf_mesh);
- gltf_node->mesh = mesh_i;
- gltf_node->xform = csg->get_meshes()[0];
- gltf_node->set_name(_gen_unique_name(state, csg->get_name()));
+ GLTFMeshIndex mesh_i = p_state->meshes.size();
+ p_state->meshes.push_back(gltf_mesh);
+ p_gltf_node->mesh = mesh_i;
+ p_gltf_node->xform = csg->get_meshes()[0];
+ p_gltf_node->set_name(_gen_unique_name(p_state, csg->get_name()));
}
#endif // MODULE_CSG_ENABLED
-void GLTFDocument::_create_gltf_node(Ref<GLTFState> state, Node *p_scene_parent, GLTFNodeIndex current_node_i,
- GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> gltf_node) {
- state->scene_nodes.insert(current_node_i, p_scene_parent);
- state->nodes.push_back(gltf_node);
- ERR_FAIL_COND(current_node_i == p_parent_node_index);
- state->nodes.write[current_node_i]->parent = p_parent_node_index;
+void GLTFDocument::_create_gltf_node(Ref<GLTFState> p_state, Node *p_scene_parent, GLTFNodeIndex p_current_node_i,
+ GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> p_gltf_node) {
+ p_state->scene_nodes.insert(p_current_node_i, p_scene_parent);
+ p_state->nodes.push_back(p_gltf_node);
+ ERR_FAIL_COND(p_current_node_i == p_parent_node_index);
+ p_state->nodes.write[p_current_node_i]->parent = p_parent_node_index;
if (p_parent_node_index == -1) {
return;
}
- state->nodes.write[p_parent_node_index]->children.push_back(current_node_i);
+ p_state->nodes.write[p_parent_node_index]->children.push_back(p_current_node_i);
}
-void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref<GLTFState> state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
- ERR_FAIL_COND(!animation_player);
- state->animation_players.push_back(animation_player);
- print_verbose(String("glTF: Converting animation player: ") + animation_player->get_name());
+void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *p_animation_player, Ref<GLTFState> p_state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
+ ERR_FAIL_COND(!p_animation_player);
+ p_state->animation_players.push_back(p_animation_player);
+ print_verbose(String("glTF: Converting animation player: ") + p_animation_player->get_name());
}
-void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) {
- retflag = true;
+void GLTFDocument::_check_visibility(Node *p_node, bool &r_retflag) {
+ r_retflag = true;
Node3D *spatial = Object::cast_to<Node3D>(p_node);
Node2D *node_2d = Object::cast_to<Node2D>(p_node);
if (node_2d && !node_2d->is_visible()) {
@@ -5370,32 +5362,32 @@ void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) {
if (spatial && !spatial->is_visible()) {
return;
}
- retflag = false;
+ r_retflag = false;
}
-void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
+void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) {
ERR_FAIL_COND(!camera);
- GLTFCameraIndex camera_index = _convert_camera(state, camera);
+ GLTFCameraIndex camera_index = _convert_camera(p_state, camera);
if (camera_index != -1) {
- gltf_node->camera = camera_index;
+ p_gltf_node->camera = camera_index;
}
}
-void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
+void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) {
ERR_FAIL_COND(!light);
- GLTFLightIndex light_index = _convert_light(state, light);
+ GLTFLightIndex light_index = _convert_light(p_state, light);
if (light_index != -1) {
- gltf_node->light = light_index;
+ p_gltf_node->light = light_index;
}
}
#ifdef MODULE_GRIDMAP_ENABLED
-void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) {
Array cells = p_grid_map->get_used_cells();
for (int32_t k = 0; k < cells.size(); k++) {
GLTFNode *new_gltf_node = memnew(GLTFNode);
- gltf_node->children.push_back(state->nodes.size());
- state->nodes.push_back(new_gltf_node);
+ p_gltf_node->children.push_back(p_state->nodes.size());
+ p_state->nodes.push_back(new_gltf_node);
Vector3 cell_location = cells[k];
int32_t cell = p_grid_map->get_cell_item(
Vector3(cell_location.x, cell_location.y, cell_location.z));
@@ -5411,10 +5403,10 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
gltf_mesh->set_mesh(_mesh_to_importer_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell)));
- new_gltf_node->mesh = state->meshes.size();
- state->meshes.push_back(gltf_mesh);
+ new_gltf_node->mesh = p_state->meshes.size();
+ p_state->meshes.push_back(gltf_mesh);
new_gltf_node->xform = cell_xform * p_grid_map->get_transform();
- new_gltf_node->set_name(_gen_unique_name(state, p_grid_map->get_mesh_library()->get_item_name(cell)));
+ new_gltf_node->set_name(_gen_unique_name(p_state, p_grid_map->get_mesh_library()->get_item_name(cell)));
}
}
#endif // MODULE_GRIDMAP_ENABLED
@@ -5423,7 +5415,7 @@ void GLTFDocument::_convert_multi_mesh_instance_to_gltf(
MultiMeshInstance3D *p_multi_mesh_instance,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_node_index,
- Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+ Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) {
ERR_FAIL_COND(!p_multi_mesh_instance);
Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh();
if (multi_mesh.is_null()) {
@@ -5459,8 +5451,8 @@ void GLTFDocument::_convert_multi_mesh_instance_to_gltf(
blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i));
}
gltf_mesh->set_mesh(importer_mesh);
- GLTFMeshIndex mesh_index = state->meshes.size();
- state->meshes.push_back(gltf_mesh);
+ GLTFMeshIndex mesh_index = p_state->meshes.size();
+ p_state->meshes.push_back(gltf_mesh);
for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
instance_i++) {
Transform3D transform;
@@ -5482,22 +5474,22 @@ void GLTFDocument::_convert_multi_mesh_instance_to_gltf(
new_gltf_node.instantiate();
new_gltf_node->mesh = mesh_index;
new_gltf_node->xform = transform;
- new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name()));
- gltf_node->children.push_back(state->nodes.size());
- state->nodes.push_back(new_gltf_node);
+ new_gltf_node->set_name(_gen_unique_name(p_state, p_multi_mesh_instance->get_name()));
+ p_gltf_node->children.push_back(p_state->nodes.size());
+ p_state->nodes.push_back(new_gltf_node);
}
}
-void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) {
+void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) {
Skeleton3D *skeleton = p_skeleton3d;
Ref<GLTFSkeleton> gltf_skeleton;
gltf_skeleton.instantiate();
- // GLTFSkeleton is only used to hold internal state data. It will not be written to the document.
+ // GLTFSkeleton is only used to hold internal p_state data. It will not be written to the document.
//
gltf_skeleton->godot_skeleton = skeleton;
- GLTFSkeletonIndex skeleton_i = state->skeletons.size();
- state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i;
- state->skeletons.push_back(gltf_skeleton);
+ GLTFSkeletonIndex skeleton_i = p_state->skeletons.size();
+ p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i;
+ p_state->skeletons.push_back(gltf_skeleton);
BoneId bone_count = skeleton->get_bone_count();
for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) {
@@ -5505,15 +5497,15 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS
joint_node.instantiate();
// Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node
// names to be unique regardless of whether or not they are used as joints.
- joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i)));
+ joint_node->set_name(_gen_unique_name(p_state, skeleton->get_bone_name(bone_i)));
Transform3D xform = skeleton->get_bone_pose(bone_i);
joint_node->scale = xform.basis.get_scale();
joint_node->rotation = xform.basis.get_rotation_quaternion();
joint_node->position = xform.origin;
joint_node->joint = true;
- GLTFNodeIndex current_node_i = state->nodes.size();
- state->scene_nodes.insert(current_node_i, skeleton);
- state->nodes.push_back(joint_node);
+ GLTFNodeIndex current_node_i = p_state->nodes.size();
+ p_state->scene_nodes.insert(current_node_i, skeleton);
+ p_state->nodes.push_back(joint_node);
gltf_skeleton->joints.push_back(current_node_i);
if (skeleton->get_bone_parent(bone_i) == -1) {
@@ -5526,23 +5518,23 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS
BoneId parent_bone_id = skeleton->get_bone_parent(bone_i);
if (parent_bone_id == -1) {
if (p_parent_node_index != -1) {
- state->nodes.write[current_node_i]->parent = p_parent_node_index;
- state->nodes.write[p_parent_node_index]->children.push_back(current_node_i);
+ p_state->nodes.write[current_node_i]->parent = p_parent_node_index;
+ p_state->nodes.write[p_parent_node_index]->children.push_back(current_node_i);
}
} else {
GLTFNodeIndex parent_node_i = gltf_skeleton->godot_bone_node[parent_bone_id];
- state->nodes.write[current_node_i]->parent = parent_node_i;
- state->nodes.write[parent_node_i]->children.push_back(current_node_i);
+ p_state->nodes.write[current_node_i]->parent = parent_node_i;
+ p_state->nodes.write[parent_node_i]->children.push_back(current_node_i);
}
}
// Remove placeholder skeleton3d node by not creating the gltf node
// Skins are per mesh
for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) {
- _convert_scene_node(state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index);
+ _convert_scene_node(p_state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index);
}
}
-void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) {
+void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) {
Skeleton3D *skeleton;
// Note that relative transforms to external skeletons and pose overrides are not supported.
if (p_bone_attachment->get_use_external_skeleton()) {
@@ -5551,8 +5543,8 @@ void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_att
skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_parent());
}
GLTFSkeletonIndex skel_gltf_i = -1;
- if (skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) {
- skel_gltf_i = state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()];
+ if (skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) {
+ skel_gltf_i = p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()];
}
int bone_idx = -1;
if (skeleton != nullptr) {
@@ -5563,28 +5555,28 @@ void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_att
}
GLTFNodeIndex par_node_index = p_parent_node_index;
if (skeleton != nullptr && bone_idx != -1 && skel_gltf_i != -1) {
- Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_gltf_i];
+ Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_gltf_i];
gltf_skeleton->bone_attachments.push_back(p_bone_attachment);
par_node_index = gltf_skeleton->joints[bone_idx];
}
for (int node_i = 0; node_i < p_bone_attachment->get_child_count(); node_i++) {
- _convert_scene_node(state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index);
+ _convert_scene_node(p_state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index);
}
}
-void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
- GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(state, p_scene_parent);
+void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) {
+ GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(p_state, p_scene_parent);
if (gltf_mesh_index != -1) {
- gltf_node->mesh = gltf_mesh_index;
+ p_gltf_node->mesh = gltf_mesh_index;
}
}
-void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
+void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[node_index];
if (gltf_node->skeleton >= 0) {
- _generate_skeleton_bone_node(state, scene_parent, scene_root, node_index);
+ _generate_skeleton_bone_node(p_state, scene_parent, scene_root, node_index);
return;
}
@@ -5598,13 +5590,13 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
// skinned meshes must not be placed in a bone attachment.
if (non_bone_parented_to_skeleton && gltf_node->skin < 0) {
// Bone Attachment - Parent Case
- BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent);
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, node_index, gltf_node->parent);
scene_parent->add_child(bone_attachment, true);
bone_attachment->set_owner(scene_root);
// There is no gltf_node that represent this, so just directly create a unique name
- bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D"));
+ bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D"));
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
// and attach it to the bone_attachment
@@ -5613,7 +5605,7 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
// Check if any GLTFDocumentExtension classes want to generate a node for us.
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- current_node = ext->generate_scene_node(state, gltf_node, scene_parent);
+ current_node = ext->generate_scene_node(p_state, gltf_node, scene_parent);
if (current_node) {
break;
}
@@ -5621,13 +5613,13 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
// If none of our GLTFDocumentExtension classes generated us a node, we generate one.
if (!current_node) {
if (gltf_node->mesh >= 0) {
- current_node = _generate_mesh_instance(state, node_index);
+ current_node = _generate_mesh_instance(p_state, node_index);
} else if (gltf_node->camera >= 0) {
- current_node = _generate_camera(state, node_index);
+ current_node = _generate_camera(p_state, node_index);
} else if (gltf_node->light >= 0) {
- current_node = _generate_light(state, node_index);
+ current_node = _generate_light(p_state, node_index);
} else {
- current_node = _generate_spatial(state, node_index);
+ current_node = _generate_spatial(p_state, node_index);
}
}
// Add the node we generated and set the owner to the scene root.
@@ -5640,45 +5632,45 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
current_node->set_transform(gltf_node->xform);
current_node->set_name(gltf_node->get_name());
- state->scene_nodes.insert(node_index, current_node);
+ p_state->scene_nodes.insert(node_index, current_node);
for (int i = 0; i < gltf_node->children.size(); ++i) {
- _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]);
+ _generate_scene_node(p_state, current_node, scene_root, gltf_node->children[i]);
}
}
-void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> gltf_node = state->nodes[node_index];
+void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, Node *p_scene_parent, Node3D *p_scene_root, const GLTFNodeIndex p_node_index) {
+ Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index];
Node3D *current_node = nullptr;
- Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
+ Skeleton3D *skeleton = p_state->skeletons[gltf_node->skeleton]->godot_skeleton;
// In this case, this node is already a bone in skeleton.
const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0);
const bool requires_extra_node = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0);
- Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent);
+ Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent);
if (active_skeleton != skeleton) {
if (active_skeleton) {
// Bone Attachment - Direct Parented Skeleton Case
- BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent);
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent);
- scene_parent->add_child(bone_attachment, true);
- bone_attachment->set_owner(scene_root);
+ p_scene_parent->add_child(bone_attachment, true);
+ bone_attachment->set_owner(p_scene_root);
// There is no gltf_node that represent this, so just directly create a unique name
- bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D"));
+ bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D"));
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
// and attach it to the bone_attachment
- scene_parent = bone_attachment;
- WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", node_index));
+ p_scene_parent = bone_attachment;
+ WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", p_node_index));
}
// Add it to the scene if it has not already been added
if (skeleton->get_parent() == nullptr) {
- scene_parent->add_child(skeleton, true);
- skeleton->set_owner(scene_root);
+ p_scene_parent->add_child(skeleton, true);
+ skeleton->set_owner(p_scene_root);
}
}
@@ -5689,22 +5681,22 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen
// skinned meshes must not be placed in a bone attachment.
if (!is_skinned_mesh) {
// Bone Attachment - Same Node Case
- BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, node_index);
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index);
- scene_parent->add_child(bone_attachment, true);
- bone_attachment->set_owner(scene_root);
+ p_scene_parent->add_child(bone_attachment, true);
+ bone_attachment->set_owner(p_scene_root);
// There is no gltf_node that represent this, so just directly create a unique name
- bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D"));
+ bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D"));
// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
// and attach it to the bone_attachment
- scene_parent = bone_attachment;
+ p_scene_parent = bone_attachment;
}
// Check if any GLTFDocumentExtension classes want to generate a node for us.
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- current_node = ext->generate_scene_node(state, gltf_node, scene_parent);
+ current_node = ext->generate_scene_node(p_state, gltf_node, p_scene_parent);
if (current_node) {
break;
}
@@ -5712,30 +5704,30 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen
// If none of our GLTFDocumentExtension classes generated us a node, we generate one.
if (!current_node) {
if (gltf_node->mesh >= 0) {
- current_node = _generate_mesh_instance(state, node_index);
+ current_node = _generate_mesh_instance(p_state, p_node_index);
} else if (gltf_node->camera >= 0) {
- current_node = _generate_camera(state, node_index);
+ current_node = _generate_camera(p_state, p_node_index);
} else if (gltf_node->light >= 0) {
- current_node = _generate_light(state, node_index);
+ current_node = _generate_light(p_state, p_node_index);
} else {
- current_node = _generate_spatial(state, node_index);
+ current_node = _generate_spatial(p_state, p_node_index);
}
}
// Add the node we generated and set the owner to the scene root.
- scene_parent->add_child(current_node, true);
- if (current_node != scene_root) {
+ p_scene_parent->add_child(current_node, true);
+ if (current_node != p_scene_root) {
Array args;
- args.append(scene_root);
+ args.append(p_scene_root);
current_node->propagate_call(StringName("set_owner"), args);
}
// Do not set transform here. Transform is already applied to our bone.
current_node->set_name(gltf_node->get_name());
}
- state->scene_nodes.insert(node_index, current_node);
+ p_state->scene_nodes.insert(p_node_index, current_node);
for (int i = 0; i < gltf_node->children.size(); ++i) {
- _generate_scene_node(state, active_skeleton, scene_root, gltf_node->children[i]);
+ _generate_scene_node(p_state, active_skeleton, p_scene_root, gltf_node->children[i]);
}
}
@@ -5860,13 +5852,13 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T
ERR_FAIL_V(p_values[0]);
}
-void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const float bake_fps, const bool trimming) {
- Ref<GLTFAnimation> anim = state->animations[index];
+void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, const GLTFAnimationIndex p_index, const float p_bake_fps, const bool p_trimming) {
+ Ref<GLTFAnimation> anim = p_state->animations[p_index];
String anim_name = anim->get_name();
if (anim_name.is_empty()) {
// No node represent these, and they are not in the hierarchy, so just make a unique name
- anim_name = _gen_unique_name(state, "Animation");
+ anim_name = _gen_unique_name(p_state, "Animation");
}
Ref<Animation> animation;
@@ -5877,7 +5869,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
animation->set_loop_mode(Animation::LOOP_LINEAR);
}
- double anim_start = trimming ? INFINITY : 0.0;
+ double anim_start = p_trimming ? INFINITY : 0.0;
double anim_end = 0.0;
for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) {
@@ -5889,26 +5881,26 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
GLTFNodeIndex node_index = track_i.key;
- const Ref<GLTFNode> gltf_node = state->nodes[track_i.key];
+ const Ref<GLTFNode> gltf_node = p_state->nodes[track_i.key];
- Node *root = ap->get_parent();
+ Node *root = p_animation_player->get_parent();
ERR_FAIL_COND(root == nullptr);
- HashMap<GLTFNodeIndex, Node *>::Iterator node_element = state->scene_nodes.find(node_index);
+ HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index);
ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation", node_index));
node_path = root->get_path_to(node_element->value);
if (gltf_node->skeleton >= 0) {
- const Skeleton3D *sk = state->skeletons[gltf_node->skeleton]->godot_skeleton;
+ const Skeleton3D *sk = p_state->skeletons[gltf_node->skeleton]->godot_skeleton;
ERR_FAIL_COND(sk == nullptr);
- const String path = ap->get_parent()->get_path_to(sk);
+ const String path = p_animation_player->get_parent()->get_path_to(sk);
const String bone = gltf_node->get_name();
transform_node_path = path + ":" + bone;
} else {
transform_node_path = node_path;
}
- if (trimming) {
+ if (p_trimming) {
for (int i = 0; i < track.rotation_track.times.size(); i++) {
anim_start = MIN(anim_start, track.rotation_track.times[i]);
anim_end = MAX(anim_end, track.rotation_track.times[i]);
@@ -5955,7 +5947,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
int scale_idx = -1;
if (track.position_track.values.size()) {
- Vector3 base_pos = state->nodes[track_i.key]->position;
+ Vector3 base_pos = p_state->nodes[track_i.key]->position;
bool not_default = false; //discard the track if all it contains is default values
for (int i = 0; i < track.position_track.times.size(); i++) {
Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i];
@@ -5974,7 +5966,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
if (track.rotation_track.values.size()) {
- Quaternion base_rot = state->nodes[track_i.key]->rotation.normalized();
+ Quaternion base_rot = p_state->nodes[track_i.key]->rotation.normalized();
bool not_default = false; //discard the track if all it contains is default values
for (int i = 0; i < track.rotation_track.times.size(); i++) {
Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized();
@@ -5992,7 +5984,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
if (track.scale_track.values.size()) {
- Vector3 base_scale = state->nodes[track_i.key]->scale;
+ Vector3 base_scale = p_state->nodes[track_i.key]->scale;
bool not_default = false; //discard the track if all it contains is default values
for (int i = 0; i < track.scale_track.times.size(); i++) {
Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i];
@@ -6010,7 +6002,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
- const double increment = 1.0 / bake_fps;
+ const double increment = 1.0 / p_bake_fps;
double time = anim_start;
Vector3 base_pos;
@@ -6018,15 +6010,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Vector3 base_scale = Vector3(1, 1, 1);
if (rotation_idx == -1) {
- base_rot = state->nodes[track_i.key]->rotation.normalized();
+ base_rot = p_state->nodes[track_i.key]->rotation.normalized();
}
if (position_idx == -1) {
- base_pos = state->nodes[track_i.key]->position;
+ base_pos = p_state->nodes[track_i.key]->position;
}
if (scale_idx == -1) {
- base_scale = state->nodes[track_i.key]->scale;
+ base_scale = p_state->nodes[track_i.key]->scale;
}
bool last = false;
@@ -6062,8 +6054,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
for (int i = 0; i < track.weight_tracks.size(); i++) {
- ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= state->meshes.size());
- Ref<GLTFMesh> mesh = state->meshes[gltf_node->mesh];
+ ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= p_state->meshes.size());
+ Ref<GLTFMesh> mesh = p_state->meshes[gltf_node->mesh];
ERR_CONTINUE(mesh.is_null());
ERR_CONTINUE(mesh->get_mesh().is_null());
ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null());
@@ -6086,7 +6078,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
} else {
// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
- const double increment = 1.0 / bake_fps;
+ const double increment = 1.0 / p_bake_fps;
double time = 0.0;
bool last = false;
while (true) {
@@ -6108,23 +6100,23 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
animation->set_length(anim_end - anim_start);
Ref<AnimationLibrary> library;
- if (!ap->has_animation_library("")) {
+ if (!p_animation_player->has_animation_library("")) {
library.instantiate();
- ap->add_animation_library("", library);
+ p_animation_player->add_animation_library("", library);
} else {
- library = ap->get_animation_library("");
+ library = p_animation_player->get_animation_library("");
}
library->add_animation(anim_name, animation);
}
-void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
- for (GLTFNodeIndex mi_node_i = 0; mi_node_i < state->nodes.size(); ++mi_node_i) {
- Ref<GLTFNode> node = state->nodes[mi_node_i];
+void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> p_state) {
+ for (GLTFNodeIndex mi_node_i = 0; mi_node_i < p_state->nodes.size(); ++mi_node_i) {
+ Ref<GLTFNode> node = p_state->nodes[mi_node_i];
if (node->mesh < 0) {
continue;
}
- HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(mi_node_i);
+ HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = p_state->scene_nodes.find(mi_node_i);
if (!mi_element) {
continue;
}
@@ -6155,10 +6147,10 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
if (skel_node != nullptr) {
godot_skeleton = cast_to<Skeleton3D>(skel_node);
}
- if (godot_skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) {
+ if (godot_skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) {
// This is a skinned mesh. If the mesh has no ARRAY_WEIGHTS or ARRAY_BONES, it will be invisible.
- const GLTFSkeletonIndex skeleton_gltf_i = state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()];
- Ref<GLTFSkeleton> gltf_skeleton = state->skeletons[skeleton_gltf_i];
+ const GLTFSkeletonIndex skeleton_gltf_i = p_state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()];
+ Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons[skeleton_gltf_i];
int bone_cnt = skeleton->get_bone_count();
ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size());
@@ -6172,8 +6164,8 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
if (!gltf_skeleton->roots.is_empty()) {
root_gltf_i = gltf_skeleton->roots[0];
}
- if (state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) {
- skin_gltf_i = state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key];
+ if (p_state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) {
+ skin_gltf_i = p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key];
} else {
if (skin.is_null()) {
// Note that gltf_skin_key should remain null, so these can share a reference.
@@ -6210,9 +6202,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
gltf_skin->joint_i_to_bone_i[bind_i] = bone_i;
gltf_skin->joint_i_to_name[bind_i] = bind_name;
}
- skin_gltf_i = state->skins.size();
- state->skins.push_back(gltf_skin);
- state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i;
+ skin_gltf_i = p_state->skins.size();
+ p_state->skins.push_back(gltf_skin);
+ p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i;
}
node->skin = skin_gltf_i;
node->skeleton = skeleton_gltf_i;
@@ -6220,14 +6212,14 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
}
}
-float GLTFDocument::solve_metallic(float p_dielectric_specular, float diffuse, float specular, float p_one_minus_specular_strength) {
- if (specular <= p_dielectric_specular) {
+float GLTFDocument::solve_metallic(float p_dielectric_specular, float p_diffuse, float p_specular, float p_one_minus_specular_strength) {
+ if (p_specular <= p_dielectric_specular) {
return 0.0f;
}
const float a = p_dielectric_specular;
- const float b = diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + specular - 2.0f * p_dielectric_specular;
- const float c = p_dielectric_specular - specular;
+ const float b = p_diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + p_specular - 2.0f * p_dielectric_specular;
+ const float c = p_dielectric_specular - p_specular;
const float D = b * b - 4.0f * a * c;
return CLAMP((-b + Math::sqrt(D)) / (2.0f * a), 0.0f, 1.0f);
}
@@ -6251,21 +6243,21 @@ float GLTFDocument::get_max_component(const Color &p_color) {
return MAX(MAX(r, g), b);
}
-void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_root) {
- for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); ++node_i) {
- Ref<GLTFNode> node = state->nodes[node_i];
+void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene_root) {
+ for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) {
+ Ref<GLTFNode> node = p_state->nodes[node_i];
if (node->skin >= 0 && node->mesh >= 0) {
const GLTFSkinIndex skin_i = node->skin;
- HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(node_i);
+ HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = p_state->scene_nodes.find(node_i);
ERR_CONTINUE_MSG(!mi_element, vformat("Unable to find node %d", node_i));
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->value);
ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->value->get_class_name()));
- const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
- Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
+ const GLTFSkeletonIndex skel_i = p_state->skins.write[node->skin]->skeleton;
+ Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i];
Skeleton3D *skeleton = gltf_skeleton->godot_skeleton;
ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d", node_i, skin_i));
@@ -6273,14 +6265,14 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
skeleton->add_child(mi, true);
mi->set_owner(skeleton->get_owner());
- mi->set_skin(state->skins.write[skin_i]->godot_skin);
+ mi->set_skin(p_state->skins.write[skin_i]->godot_skin);
mi->set_skeleton_path(mi->get_path_to(skeleton));
mi->set_transform(Transform3D());
}
}
}
-GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) {
+GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> p_state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) {
Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i);
GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
@@ -6426,11 +6418,11 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
return p_track;
}
-void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name) {
- Ref<Animation> animation = ap->get_animation(p_animation_track_name);
+void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name) {
+ Ref<Animation> animation = p_animation_player->get_animation(p_animation_track_name);
Ref<GLTFAnimation> gltf_animation;
gltf_animation.instantiate();
- gltf_animation->set_name(_gen_unique_name(state, p_animation_track_name));
+ gltf_animation->set_name(_gen_unique_name(p_state, p_animation_track_name));
for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) {
if (!animation->track_is_enabled(track_i)) {
@@ -6440,8 +6432,8 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (String(orig_track_path).contains(":position")) {
const Vector<String> node_suffix = String(orig_track_path).split(":position");
const NodePath path = node_suffix[0];
- const Node *node = ap->get_parent()->get_node_or_null(path);
- for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : state->scene_nodes) {
+ const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : p_state->scene_nodes) {
if (position_scene_node_i.value == node) {
GLTFNodeIndex node_index = position_scene_node_i.key;
HashMap<int, GLTFAnimation::Track>::Iterator position_track_i = gltf_animation->get_tracks().find(node_index);
@@ -6449,15 +6441,15 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (position_track_i) {
track = position_track_i->value;
}
- track = _convert_animation_track(state, track, animation, track_i, node_index);
+ track = _convert_animation_track(p_state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
} else if (String(orig_track_path).contains(":rotation_degrees")) {
const Vector<String> node_suffix = String(orig_track_path).split(":rotation_degrees");
const NodePath path = node_suffix[0];
- const Node *node = ap->get_parent()->get_node_or_null(path);
- for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : state->scene_nodes) {
+ const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : p_state->scene_nodes) {
if (rotation_degree_scene_node_i.value == node) {
GLTFNodeIndex node_index = rotation_degree_scene_node_i.key;
HashMap<int, GLTFAnimation::Track>::Iterator rotation_degree_track_i = gltf_animation->get_tracks().find(node_index);
@@ -6465,15 +6457,15 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (rotation_degree_track_i) {
track = rotation_degree_track_i->value;
}
- track = _convert_animation_track(state, track, animation, track_i, node_index);
+ track = _convert_animation_track(p_state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
} else if (String(orig_track_path).contains(":scale")) {
const Vector<String> node_suffix = String(orig_track_path).split(":scale");
const NodePath path = node_suffix[0];
- const Node *node = ap->get_parent()->get_node_or_null(path);
- for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : state->scene_nodes) {
+ const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : p_state->scene_nodes) {
if (scale_scene_node_i.value == node) {
GLTFNodeIndex node_index = scale_scene_node_i.key;
HashMap<int, GLTFAnimation::Track>::Iterator scale_track_i = gltf_animation->get_tracks().find(node_index);
@@ -6481,18 +6473,18 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (scale_track_i) {
track = scale_track_i->value;
}
- track = _convert_animation_track(state, track, animation, track_i, node_index);
+ track = _convert_animation_track(p_state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
} else if (String(orig_track_path).contains(":transform")) {
const Vector<String> node_suffix = String(orig_track_path).split(":transform");
const NodePath path = node_suffix[0];
- const Node *node = ap->get_parent()->get_node_or_null(path);
- for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : state->scene_nodes) {
+ const Node *node = p_animation_player->get_parent()->get_node_or_null(path);
+ for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : p_state->scene_nodes) {
if (transform_track_i.value == node) {
GLTFAnimation::Track track;
- track = _convert_animation_track(state, track, animation, track_i, transform_track_i.key);
+ track = _convert_animation_track(p_state, track, animation, track_i, transform_track_i.key);
gltf_animation->get_tracks().insert(transform_track_i.key, track);
}
}
@@ -6500,12 +6492,12 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const Vector<String> node_suffix = String(orig_track_path).split(":");
const NodePath path = node_suffix[0];
const String suffix = node_suffix[1];
- Node *node = ap->get_parent()->get_node_or_null(path);
+ Node *node = p_animation_player->get_parent()->get_node_or_null(path);
MeshInstance3D *mi = cast_to<MeshInstance3D>(node);
Ref<Mesh> mesh = mi->get_mesh();
ERR_CONTINUE(mesh.is_null());
int32_t mesh_index = -1;
- for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : state->scene_nodes) {
+ for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : p_state->scene_nodes) {
if (mesh_track_i.value == node) {
mesh_index = mesh_track_i.key;
}
@@ -6558,15 +6550,15 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const String node = node_suffix[0];
const NodePath node_path = node;
const String suffix = node_suffix[1];
- Node *godot_node = ap->get_parent()->get_node_or_null(node_path);
+ Node *godot_node = p_animation_player->get_parent()->get_node_or_null(node_path);
Skeleton3D *skeleton = nullptr;
GLTFSkeletonIndex skeleton_gltf_i = -1;
- for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) {
- if (state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) {
- skeleton = state->skeletons[skeleton_i]->godot_skeleton;
+ for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < p_state->skeletons.size(); skeleton_i++) {
+ if (p_state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) {
+ skeleton = p_state->skeletons[skeleton_i]->godot_skeleton;
skeleton_gltf_i = skeleton_i;
ERR_CONTINUE(!skeleton);
- Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i];
+ Ref<GLTFSkeleton> skeleton_gltf = p_state->skeletons[skeleton_gltf_i];
int32_t bone = skeleton->find_bone(suffix);
ERR_CONTINUE(bone == -1);
if (!skeleton_gltf->godot_bone_node.has(bone)) {
@@ -6578,14 +6570,14 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (property_track_i) {
track = property_track_i->value;
}
- track = _convert_animation_track(state, track, animation, track_i, node_i);
+ track = _convert_animation_track(p_state, track, animation, track_i, node_i);
gltf_animation->get_tracks()[node_i] = track;
}
}
} else if (!String(orig_track_path).contains(":")) {
- ERR_CONTINUE(!ap->get_parent());
- Node *godot_node = ap->get_parent()->get_node_or_null(orig_track_path);
- for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) {
+ ERR_CONTINUE(!p_animation_player->get_parent());
+ Node *godot_node = p_animation_player->get_parent()->get_node_or_null(orig_track_path);
+ for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : p_state->scene_nodes) {
if (scene_node_i.value == godot_node) {
GLTFNodeIndex node_i = scene_node_i.key;
HashMap<int, GLTFAnimation::Track>::Iterator node_track_i = gltf_animation->get_tracks().find(node_i);
@@ -6593,7 +6585,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (node_track_i) {
track = node_track_i->value;
}
- track = _convert_animation_track(state, track, animation, track_i, node_i);
+ track = _convert_animation_track(p_state, track, animation, track_i, node_i);
gltf_animation->get_tracks()[node_i] = track;
break;
}
@@ -6601,42 +6593,42 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
if (gltf_animation->get_tracks().size()) {
- state->animations.push_back(gltf_animation);
+ p_state->animations.push_back(gltf_animation);
}
}
-Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f) {
+Error GLTFDocument::_parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file) {
Error err;
- if (f.is_null()) {
+ if (p_file.is_null()) {
return FAILED;
}
- f->seek(0);
- uint32_t magic = f->get_32();
+ p_file->seek(0);
+ uint32_t magic = p_file->get_32();
if (magic == 0x46546C67) {
//binary file
//text file
- f->seek(0);
- err = _parse_glb(f, state);
+ p_file->seek(0);
+ err = _parse_glb(p_file, p_state);
if (err != OK) {
return err;
}
} else {
- f->seek(0);
- String text = f->get_as_utf8_string();
+ p_file->seek(0);
+ String text = p_file->get_as_utf8_string();
JSON json;
err = json.parse(text);
if (err != OK) {
_err_print_error("", "", json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT);
}
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- state->json = json.get_data();
+ p_state->json = json.get_data();
}
- if (!state->json.has("asset")) {
+ if (!p_state->json.has("asset")) {
return ERR_PARSE_ERROR;
}
- Dictionary asset = state->json["asset"];
+ Dictionary asset = p_state->json["asset"];
if (!asset.has("version")) {
return ERR_PARSE_ERROR;
@@ -6644,19 +6636,19 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess>
String version = asset["version"];
- state->major_version = version.get_slice(".", 0).to_int();
- state->minor_version = version.get_slice(".", 1).to_int();
+ p_state->major_version = version.get_slice(".", 0).to_int();
+ p_state->minor_version = version.get_slice(".", 1).to_int();
document_extensions.clear();
for (Ref<GLTFDocumentExtension> ext : all_document_extensions) {
ERR_CONTINUE(ext.is_null());
- err = ext->import_preflight(state, state->json["extensionsUsed"]);
+ err = ext->import_preflight(p_state, p_state->json["extensionsUsed"]);
if (err == OK) {
document_extensions.push_back(ext);
}
}
- err = _parse_gltf_state(state, p_path);
+ err = _parse_gltf_state(p_state, p_path);
ERR_FAIL_COND_V(err != OK, err);
return OK;
@@ -6702,30 +6694,30 @@ Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_
return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y));
}
-Error GLTFDocument::_serialize_version(Ref<GLTFState> state) {
+Error GLTFDocument::_serialize_version(Ref<GLTFState> p_state) {
const String version = "2.0";
- state->major_version = version.get_slice(".", 0).to_int();
- state->minor_version = version.get_slice(".", 1).to_int();
+ p_state->major_version = version.get_slice(".", 0).to_int();
+ p_state->minor_version = version.get_slice(".", 1).to_int();
Dictionary asset;
asset["version"] = version;
String hash = String(VERSION_HASH);
asset["generator"] = String(VERSION_FULL_NAME) + String("@") + (hash.is_empty() ? String("unknown") : hash);
- state->json["asset"] = asset;
+ p_state->json["asset"] = asset;
ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED);
- ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED);
+ ERR_FAIL_COND_V(!p_state->json.has("asset"), Error::FAILED);
return OK;
}
-Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
+Error GLTFDocument::_serialize_file(Ref<GLTFState> p_state, const String p_path) {
Error err = FAILED;
if (p_path.to_lower().ends_with("glb")) {
- err = _encode_buffer_glb(state, p_path);
+ err = _encode_buffer_glb(p_state, p_path);
ERR_FAIL_COND_V(err != OK, err);
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(f.is_null(), FAILED);
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(file.is_null(), FAILED);
- String json = Variant(state->json).to_json_string();
+ String json = Variant(p_state->json).to_json_string();
const uint32_t magic = 0x46546C67; // GLTF
const int32_t header_size = 12;
@@ -6736,39 +6728,39 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
const uint32_t text_chunk_type = 0x4E4F534A; //JSON
uint32_t binary_data_length = 0;
- if (state->buffers.size()) {
- binary_data_length = state->buffers[0].size();
+ if (p_state->buffers.size()) {
+ binary_data_length = p_state->buffers[0].size();
}
const uint32_t binary_chunk_length = ((binary_data_length + 3) & (~3));
const uint32_t binary_chunk_type = 0x004E4942; //BIN
- f->create(FileAccess::ACCESS_RESOURCES);
- f->store_32(magic);
- f->store_32(state->major_version); // version
- f->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length
- f->store_32(text_chunk_length);
- f->store_32(text_chunk_type);
- f->store_buffer((uint8_t *)&cs[0], cs.length());
+ file->create(FileAccess::ACCESS_RESOURCES);
+ file->store_32(magic);
+ file->store_32(p_state->major_version); // version
+ file->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length
+ file->store_32(text_chunk_length);
+ file->store_32(text_chunk_type);
+ file->store_buffer((uint8_t *)&cs[0], cs.length());
for (uint32_t pad_i = text_data_length; pad_i < text_chunk_length; pad_i++) {
- f->store_8(' ');
+ file->store_8(' ');
}
if (binary_chunk_length) {
- f->store_32(binary_chunk_length);
- f->store_32(binary_chunk_type);
- f->store_buffer(state->buffers[0].ptr(), binary_data_length);
+ file->store_32(binary_chunk_length);
+ file->store_32(binary_chunk_type);
+ file->store_buffer(p_state->buffers[0].ptr(), binary_data_length);
}
for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) {
- f->store_8(0);
+ file->store_8(0);
}
} else {
- err = _encode_buffer_bins(state, p_path);
+ err = _encode_buffer_bins(p_state, p_path);
ERR_FAIL_COND_V(err != OK, err);
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(f.is_null(), FAILED);
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(file.is_null(), FAILED);
- f->create(FileAccess::ACCESS_RESOURCES);
- String json = Variant(state->json).to_json_string();
- f->store_string(json);
+ file->create(FileAccess::ACCESS_RESOURCES);
+ String json = Variant(p_state->json).to_json_string();
+ file->store_string(json);
}
return err;
}
@@ -6793,16 +6785,16 @@ void GLTFDocument::_bind_methods() {
&GLTFDocument::unregister_gltf_document_extension);
}
-void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) {
+void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> p_state) {
// build the hierarchy
- for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
- for (int j = 0; j < state->nodes[node_i]->children.size(); j++) {
- GLTFNodeIndex child_i = state->nodes[node_i]->children[j];
- ERR_FAIL_INDEX(child_i, state->nodes.size());
- if (state->nodes.write[child_i]->parent != -1) {
+ for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) {
+ for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) {
+ GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j];
+ ERR_FAIL_INDEX(child_i, p_state->nodes.size());
+ if (p_state->nodes.write[child_i]->parent != -1) {
continue;
}
- state->nodes.write[child_i]->parent = node_i;
+ p_state->nodes.write[child_i]->parent = node_i;
}
}
}
@@ -6827,13 +6819,13 @@ void GLTFDocument::unregister_all_gltf_document_extensions() {
all_document_extensions.clear();
}
-PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error *r_err) {
- Error err = _encode_buffer_glb(state, "");
+PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) {
+ Error err = _encode_buffer_glb(p_state, "");
if (r_err) {
*r_err = err;
}
ERR_FAIL_COND_V(err != OK, PackedByteArray());
- String json = Variant(state->json).to_json_string();
+ String json = Variant(p_state->json).to_json_string();
const uint32_t magic = 0x46546C67; // GLTF
const int32_t header_size = 12;
@@ -6847,8 +6839,8 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error
const uint32_t text_chunk_type = 0x4E4F534A; //JSON
int32_t binary_data_length = 0;
- if (state->buffers.size()) {
- binary_data_length = state->buffers[0].size();
+ if (p_state->buffers.size()) {
+ binary_data_length = p_state->buffers[0].size();
}
const int32_t binary_chunk_length = binary_data_length;
const int32_t binary_chunk_type = 0x004E4942; //BIN
@@ -6856,7 +6848,7 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error
Ref<StreamPeerBuffer> buffer;
buffer.instantiate();
buffer->put_32(magic);
- buffer->put_32(state->major_version); // version
+ buffer->put_32(p_state->major_version); // version
buffer->put_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length
buffer->put_32(text_chunk_length);
buffer->put_32(text_chunk_type);
@@ -6864,204 +6856,204 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error
if (binary_chunk_length) {
buffer->put_32(binary_chunk_length);
buffer->put_32(binary_chunk_type);
- buffer->put_data(state->buffers[0].ptr(), binary_data_length);
+ buffer->put_data(p_state->buffers[0].ptr(), binary_data_length);
}
return buffer->get_data_array();
}
-PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> state) {
- ERR_FAIL_NULL_V(state, PackedByteArray());
- Error err = _serialize(state, "");
+PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> p_state) {
+ ERR_FAIL_NULL_V(p_state, PackedByteArray());
+ Error err = _serialize(p_state, "");
ERR_FAIL_COND_V(err != OK, PackedByteArray());
- PackedByteArray bytes = _serialize_glb_buffer(state, &err);
+ PackedByteArray bytes = _serialize_glb_buffer(p_state, &err);
return bytes;
}
-Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_path) {
- ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER);
- Error err = _serialize(state, p_path);
+Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ Error err = _serialize(p_state, p_path);
if (err != OK) {
return err;
}
- err = _serialize_file(state, p_path);
+ err = _serialize_file(p_state, p_path);
if (err != OK) {
return Error::FAILED;
}
return OK;
}
-Node *GLTFDocument::generate_scene(Ref<GLTFState> state, float p_bake_fps, bool p_trimming) {
- ERR_FAIL_NULL_V(state, nullptr);
- ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr);
+Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming) {
+ ERR_FAIL_NULL_V(p_state, nullptr);
+ ERR_FAIL_INDEX_V(0, p_state->root_nodes.size(), nullptr);
Error err = OK;
- GLTFNodeIndex gltf_root = state->root_nodes.write[0];
- Node *gltf_root_node = state->get_scene_node(gltf_root);
+ GLTFNodeIndex gltf_root = p_state->root_nodes.write[0];
+ Node *gltf_root_node = p_state->get_scene_node(gltf_root);
Node *root = gltf_root_node->get_parent();
ERR_FAIL_NULL_V(root, nullptr);
- _process_mesh_instances(state, root);
- if (state->get_create_animations() && state->animations.size()) {
+ _process_mesh_instances(p_state, root);
+ if (p_state->get_create_animations() && p_state->animations.size()) {
AnimationPlayer *ap = memnew(AnimationPlayer);
root->add_child(ap, true);
ap->set_owner(root);
- for (int i = 0; i < state->animations.size(); i++) {
- _import_animation(state, ap, i, p_bake_fps, p_trimming);
+ for (int i = 0; i < p_state->animations.size(); i++) {
+ _import_animation(p_state, ap, i, p_bake_fps, p_trimming);
}
}
- for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) {
+ for (KeyValue<GLTFNodeIndex, Node *> E : p_state->scene_nodes) {
ERR_CONTINUE(!E.value);
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- ERR_CONTINUE(!state->json.has("nodes"));
- Array nodes = state->json["nodes"];
+ ERR_CONTINUE(!p_state->json.has("nodes"));
+ Array nodes = p_state->json["nodes"];
ERR_CONTINUE(E.key >= nodes.size());
ERR_CONTINUE(E.key < 0);
Dictionary node_json = nodes[E.key];
- Ref<GLTFNode> gltf_node = state->nodes[E.key];
- err = ext->import_node(state, gltf_node, node_json, E.value);
+ Ref<GLTFNode> gltf_node = p_state->nodes[E.key];
+ err = ext->import_node(p_state, gltf_node, node_json, E.value);
ERR_CONTINUE(err != OK);
}
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- err = ext->import_post(state, root);
+ err = ext->import_post(p_state, root);
ERR_CONTINUE(err != OK);
}
ERR_FAIL_NULL_V(root, nullptr);
return root;
}
-Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags) {
- ERR_FAIL_COND_V(state.is_null(), FAILED);
- state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
- state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
+Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) {
+ ERR_FAIL_COND_V(p_state.is_null(), FAILED);
+ p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
document_extensions.clear();
for (Ref<GLTFDocumentExtension> ext : all_document_extensions) {
ERR_CONTINUE(ext.is_null());
- Error err = ext->export_preflight(p_node);
+ Error err = ext->export_preflight(p_state, p_node);
if (err == OK) {
document_extensions.push_back(ext);
}
}
- _convert_scene_node(state, p_node, -1, -1);
- if (!state->buffers.size()) {
- state->buffers.push_back(Vector<uint8_t>());
+ _convert_scene_node(p_state, p_node, -1, -1);
+ if (!p_state->buffers.size()) {
+ p_state->buffers.push_back(Vector<uint8_t>());
}
return OK;
}
-Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags) {
- ERR_FAIL_COND_V(state.is_null(), FAILED);
+Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags) {
+ ERR_FAIL_COND_V(p_state.is_null(), FAILED);
// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
Error err = FAILED;
- state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
- state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
+ p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
Ref<FileAccessMemory> file_access;
file_access.instantiate();
file_access->open_custom(p_bytes.ptr(), p_bytes.size());
- state->base_path = p_base_path.get_base_dir();
- err = _parse(state, state->base_path, file_access);
+ p_state->base_path = p_base_path.get_base_dir();
+ err = _parse(p_state, p_state->base_path, file_access);
ERR_FAIL_COND_V(err != OK, err);
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
- err = ext->import_post_parse(state);
+ err = ext->import_post_parse(p_state);
ERR_FAIL_COND_V(err != OK, err);
}
return OK;
}
-Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_search_path) {
+Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path) {
Error err;
/* PARSE EXTENSIONS */
- err = _parse_gltf_extensions(state);
+ err = _parse_gltf_extensions(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE SCENE */
- err = _parse_scenes(state);
+ err = _parse_scenes(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE NODES */
- err = _parse_nodes(state);
+ err = _parse_nodes(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE BUFFERS */
- err = _parse_buffers(state, p_search_path);
+ err = _parse_buffers(p_state, p_search_path);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE BUFFER VIEWS */
- err = _parse_buffer_views(state);
+ err = _parse_buffer_views(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE ACCESSORS */
- err = _parse_accessors(state);
+ err = _parse_accessors(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- if (!state->discard_meshes_and_materials) {
+ if (!p_state->discard_meshes_and_materials) {
/* PARSE IMAGES */
- err = _parse_images(state, p_search_path);
+ err = _parse_images(p_state, p_search_path);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE TEXTURE SAMPLERS */
- err = _parse_texture_samplers(state);
+ err = _parse_texture_samplers(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE TEXTURES */
- err = _parse_textures(state);
+ err = _parse_textures(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE TEXTURES */
- err = _parse_materials(state);
+ err = _parse_materials(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
}
/* PARSE SKINS */
- err = _parse_skins(state);
+ err = _parse_skins(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* DETERMINE SKELETONS */
- err = _determine_skeletons(state);
+ err = _determine_skeletons(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* CREATE SKELETONS */
- err = _create_skeletons(state);
+ err = _create_skeletons(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* CREATE SKINS */
- err = _create_skins(state);
+ err = _create_skins(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE MESHES (we have enough info now) */
- err = _parse_meshes(state);
+ err = _parse_meshes(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE LIGHTS */
- err = _parse_lights(state);
+ err = _parse_lights(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE CAMERAS */
- err = _parse_cameras(state);
+ err = _parse_cameras(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* PARSE ANIMATIONS */
- err = _parse_animations(state);
+ err = _parse_animations(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
/* ASSIGN SCENE NAMES */
- _assign_scene_names(state);
+ _assign_scene_names(p_state);
Node3D *root = memnew(Node3D);
- for (int32_t root_i = 0; root_i < state->root_nodes.size(); root_i++) {
- _generate_scene_node(state, root, root, state->root_nodes[root_i]);
+ for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) {
+ _generate_scene_node(p_state, root, root, p_state->root_nodes[root_i]);
}
return OK;
@@ -7076,15 +7068,15 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
r_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
Error err;
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN);
- ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN);
+ ERR_FAIL_NULL_V(file, ERR_FILE_CANT_OPEN);
String base_path = p_base_path;
if (base_path.is_empty()) {
base_path = p_path.get_base_dir();
}
r_state->base_path = base_path;
- err = _parse(r_state, base_path, f);
+ err = _parse(r_state, base_path, file);
ERR_FAIL_COND_V(err != OK, err);
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
@@ -7094,15 +7086,15 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
return OK;
}
-Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
- ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR);
- if (state->json.has("extensionsUsed")) {
- Vector<String> ext_array = state->json["extensionsUsed"];
- state->extensions_used = ext_array;
+Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) {
+ ERR_FAIL_NULL_V(p_state, ERR_PARSE_ERROR);
+ if (p_state->json.has("extensionsUsed")) {
+ Vector<String> ext_array = p_state->json["extensionsUsed"];
+ p_state->extensions_used = ext_array;
}
- if (state->json.has("extensionsRequired")) {
- Vector<String> ext_array = state->json["extensionsRequired"];
- state->extensions_required = ext_array;
+ if (p_state->json.has("extensionsRequired")) {
+ Vector<String> ext_array = p_state->json["extensionsRequired"];
+ p_state->extensions_required = ext_array;
}
HashSet<String> supported_extensions;
supported_extensions.insert("KHR_lights_punctual");
@@ -7116,9 +7108,9 @@ Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
}
}
Error ret = Error::OK;
- for (int i = 0; i < state->extensions_required.size(); i++) {
- if (!supported_extensions.has(state->extensions_required[i])) {
- ERR_PRINT("GLTF: Can't import file '" + state->filename + "', required extension '" + String(state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?");
+ for (int i = 0; i < p_state->extensions_required.size(); i++) {
+ if (!supported_extensions.has(p_state->extensions_required[i])) {
+ ERR_PRINT("GLTF: Can't import file '" + p_state->filename + "', required extension '" + String(p_state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?");
ret = ERR_UNAVAILABLE;
}
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 6eb38354a2..6e2d0e2fd4 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -32,13 +32,6 @@
#define GLTF_DOCUMENT_H
#include "extensions/gltf_document_extension.h"
-#include "structures/gltf_animation.h"
-
-#include "scene/3d/bone_attachment_3d.h"
-#include "scene/3d/importer_mesh_instance_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/animation/animation_player.h"
-#include "scene/resources/material.h"
#include "modules/modules_enabled.gen.h" // For csg, gridmap.
@@ -81,199 +74,199 @@ public:
static void unregister_all_gltf_document_extensions();
private:
- void _build_parent_hierachy(Ref<GLTFState> state);
+ void _build_parent_hierachy(Ref<GLTFState> p_state);
double _filter_number(double p_float);
String _get_component_type_name(const uint32_t p_component);
- int _get_component_type_size(const int component_type);
- Error _parse_scenes(Ref<GLTFState> state);
- Error _parse_nodes(Ref<GLTFState> state);
+ int _get_component_type_size(const int p_component_type);
+ Error _parse_scenes(Ref<GLTFState> p_state);
+ Error _parse_nodes(Ref<GLTFState> p_state);
String _get_type_name(const GLTFType p_component);
String _get_accessor_type_name(const GLTFType p_type);
- String _gen_unique_name(Ref<GLTFState> state, const String &p_name);
- String _sanitize_animation_name(const String &name);
- String _gen_unique_animation_name(Ref<GLTFState> state, const String &p_name);
- String _sanitize_bone_name(const String &name);
- String _gen_unique_bone_name(Ref<GLTFState> state,
- const GLTFSkeletonIndex skel_i,
+ String _gen_unique_name(Ref<GLTFState> p_state, const String &p_name);
+ String _sanitize_animation_name(const String &p_name);
+ String _gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name);
+ String _sanitize_bone_name(const String &p_name);
+ String _gen_unique_bone_name(Ref<GLTFState> p_state,
+ const GLTFSkeletonIndex p_skel_i,
const String &p_name);
- GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture,
+ GLTFTextureIndex _set_texture(Ref<GLTFState> p_state, Ref<Texture2D> p_texture,
StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats);
- Ref<Texture2D> _get_texture(Ref<GLTFState> state,
+ Ref<Texture2D> _get_texture(Ref<GLTFState> p_state,
const GLTFTextureIndex p_texture);
- GLTFTextureSamplerIndex _set_sampler_for_mode(Ref<GLTFState> state,
+ GLTFTextureSamplerIndex _set_sampler_for_mode(Ref<GLTFState> p_state,
StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats);
- Ref<GLTFTextureSampler> _get_sampler_for_texture(Ref<GLTFState> state,
+ Ref<GLTFTextureSampler> _get_sampler_for_texture(Ref<GLTFState> p_state,
const GLTFTextureIndex p_texture);
- Error _parse_json(const String &p_path, Ref<GLTFState> state);
- Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state);
- void _compute_node_heights(Ref<GLTFState> state);
- Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path);
- Error _parse_buffer_views(Ref<GLTFState> state);
+ Error _parse_json(const String &p_path, Ref<GLTFState> p_state);
+ Error _parse_glb(Ref<FileAccess> p_file, Ref<GLTFState> p_state);
+ void _compute_node_heights(Ref<GLTFState> p_state);
+ Error _parse_buffers(Ref<GLTFState> p_state, const String &p_base_path);
+ Error _parse_buffer_views(Ref<GLTFState> p_state);
GLTFType _get_type_from_str(const String &p_string);
- Error _parse_accessors(Ref<GLTFState> state);
- Error _decode_buffer_view(Ref<GLTFState> state, double *dst,
+ Error _parse_accessors(Ref<GLTFState> p_state);
+ Error _decode_buffer_view(Ref<GLTFState> p_state, double *p_dst,
const GLTFBufferViewIndex p_buffer_view,
- const int skip_every, const int skip_bytes,
- const int element_size, const int count,
- const GLTFType type, const int component_count,
- const int component_type, const int component_size,
- const bool normalized, const int byte_offset,
- const bool for_vertex);
- Vector<double> _decode_accessor(Ref<GLTFState> state,
+ const int p_skip_every, const int p_skip_bytes,
+ const int p_element_size, const int p_count,
+ const GLTFType p_type, const int p_component_count,
+ const int p_component_type, const int p_component_size,
+ const bool p_normalized, const int p_byte_offset,
+ const bool p_for_vertex);
+ Vector<double> _decode_accessor(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<float> _decode_accessor_as_floats(Ref<GLTFState> state,
+ Vector<float> _decode_accessor_as_floats(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<int> _decode_accessor_as_ints(Ref<GLTFState> state,
+ Vector<int> _decode_accessor_as_ints(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> state,
+ Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> state,
+ Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Color> _decode_accessor_as_color(Ref<GLTFState> state,
+ Vector<Color> _decode_accessor_as_color(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> state,
+ Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> state,
+ Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> state,
+ Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> state,
+ Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> p_state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Error _parse_meshes(Ref<GLTFState> state);
- Error _serialize_textures(Ref<GLTFState> state);
- Error _serialize_texture_samplers(Ref<GLTFState> state);
- Error _serialize_images(Ref<GLTFState> state, const String &p_path);
- Error _serialize_lights(Ref<GLTFState> state);
- Error _parse_images(Ref<GLTFState> state, const String &p_base_path);
- Error _parse_textures(Ref<GLTFState> state);
- Error _parse_texture_samplers(Ref<GLTFState> state);
- Error _parse_materials(Ref<GLTFState> state);
- void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material);
+ Error _parse_meshes(Ref<GLTFState> p_state);
+ Error _serialize_textures(Ref<GLTFState> p_state);
+ Error _serialize_texture_samplers(Ref<GLTFState> p_state);
+ Error _serialize_images(Ref<GLTFState> p_state, const String &p_path);
+ Error _serialize_lights(Ref<GLTFState> p_state);
+ Error _parse_images(Ref<GLTFState> p_state, const String &p_base_path);
+ Error _parse_textures(Ref<GLTFState> p_state);
+ Error _parse_texture_samplers(Ref<GLTFState> p_state);
+ Error _parse_materials(Ref<GLTFState> p_state);
+ void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> p_material);
void spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss,
Ref<BaseMaterial3D> p_material);
static void spec_gloss_to_metal_base_color(const Color &p_specular_factor,
const Color &p_diffuse,
Color &r_base_color,
float &r_metallic);
- GLTFNodeIndex _find_highest_node(Ref<GLTFState> state,
- const Vector<GLTFNodeIndex> &subset);
- bool _capture_nodes_in_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin,
- const GLTFNodeIndex node_index);
- void _capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin);
- Error _expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin);
- Error _verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin);
- Error _parse_skins(Ref<GLTFState> state);
- Error _determine_skeletons(Ref<GLTFState> state);
+ GLTFNodeIndex _find_highest_node(Ref<GLTFState> p_state,
+ const Vector<GLTFNodeIndex> &p_subset);
+ bool _capture_nodes_in_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin,
+ const GLTFNodeIndex p_node_index);
+ void _capture_nodes_for_multirooted_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin);
+ Error _expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin);
+ Error _verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin);
+ Error _parse_skins(Ref<GLTFState> p_state);
+ Error _determine_skeletons(Ref<GLTFState> p_state);
Error _reparent_non_joint_skeleton_subtrees(
- Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton,
- const Vector<GLTFNodeIndex> &non_joints);
- Error _determine_skeleton_roots(Ref<GLTFState> state,
- const GLTFSkeletonIndex skel_i);
- Error _create_skeletons(Ref<GLTFState> state);
- Error _map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> state);
- Error _serialize_skins(Ref<GLTFState> state);
- Error _create_skins(Ref<GLTFState> state);
- bool _skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_b);
- void _remove_duplicate_skins(Ref<GLTFState> state);
- Error _serialize_cameras(Ref<GLTFState> state);
- Error _parse_cameras(Ref<GLTFState> state);
- Error _parse_lights(Ref<GLTFState> state);
- Error _parse_animations(Ref<GLTFState> state);
- Error _serialize_animations(Ref<GLTFState> state);
- BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> state,
- Skeleton3D *skeleton,
- const GLTFNodeIndex node_index,
- const GLTFNodeIndex bone_index);
- ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- Light3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index);
- void _assign_scene_names(Ref<GLTFState> state);
+ Ref<GLTFState> p_state, Ref<GLTFSkeleton> p_skeleton,
+ const Vector<GLTFNodeIndex> &p_non_joints);
+ Error _determine_skeleton_roots(Ref<GLTFState> p_state,
+ const GLTFSkeletonIndex p_skel_i);
+ Error _create_skeletons(Ref<GLTFState> p_state);
+ Error _map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> p_state);
+ Error _serialize_skins(Ref<GLTFState> p_state);
+ Error _create_skins(Ref<GLTFState> p_state);
+ bool _skins_are_same(const Ref<Skin> p_skin_a, const Ref<Skin> p_skin_b);
+ void _remove_duplicate_skins(Ref<GLTFState> p_state);
+ Error _serialize_cameras(Ref<GLTFState> p_state);
+ Error _parse_cameras(Ref<GLTFState> p_state);
+ Error _parse_lights(Ref<GLTFState> p_state);
+ Error _parse_animations(Ref<GLTFState> p_state);
+ Error _serialize_animations(Ref<GLTFState> p_state);
+ BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> p_state,
+ Skeleton3D *p_skeleton,
+ const GLTFNodeIndex p_node_index,
+ const GLTFNodeIndex p_bone_index);
+ ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
+ Camera3D *_generate_camera(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
+ Light3D *_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
+ Node3D *_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
+ void _assign_scene_names(Ref<GLTFState> p_state);
template <class T>
T _interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values,
const float p_time,
const GLTFAnimation::Interpolation p_interp);
- GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> p_state,
const Vector<Quaternion> p_attribs,
const bool p_for_vertex);
- GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> p_state,
const Vector<Color> p_attribs,
const bool p_for_vertex);
- GLTFAccessorIndex _encode_accessor_as_joints(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_joints(Ref<GLTFState> p_state,
const Vector<Color> p_attribs,
const bool p_for_vertex);
- GLTFAccessorIndex _encode_accessor_as_floats(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_floats(Ref<GLTFState> p_state,
const Vector<real_t> p_attribs,
const bool p_for_vertex);
- GLTFAccessorIndex _encode_accessor_as_vec2(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_vec2(Ref<GLTFState> p_state,
const Vector<Vector2> p_attribs,
const bool p_for_vertex);
- void _calc_accessor_vec2_min_max(int i, const int element_count, Vector<double> &type_max, Vector2 attribs, Vector<double> &type_min) {
- if (i == 0) {
- for (int32_t type_i = 0; type_i < element_count; type_i++) {
- type_max.write[type_i] = attribs[(i * element_count) + type_i];
- type_min.write[type_i] = attribs[(i * element_count) + type_i];
+ void _calc_accessor_vec2_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector2 p_attribs, Vector<double> &p_type_min) {
+ if (p_i == 0) {
+ for (int32_t type_i = 0; type_i < p_element_count; type_i++) {
+ p_type_max.write[type_i] = p_attribs[(p_i * p_element_count) + type_i];
+ p_type_min.write[type_i] = p_attribs[(p_i * p_element_count) + type_i];
}
}
- for (int32_t type_i = 0; type_i < element_count; type_i++) {
- type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]);
- type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]);
- type_max.write[type_i] = _filter_number(type_max.write[type_i]);
- type_min.write[type_i] = _filter_number(type_min.write[type_i]);
+ for (int32_t type_i = 0; type_i < p_element_count; type_i++) {
+ p_type_max.write[type_i] = MAX(p_attribs[(p_i * p_element_count) + type_i], p_type_max[type_i]);
+ p_type_min.write[type_i] = MIN(p_attribs[(p_i * p_element_count) + type_i], p_type_min[type_i]);
+ p_type_max.write[type_i] = _filter_number(p_type_max.write[type_i]);
+ p_type_min.write[type_i] = _filter_number(p_type_min.write[type_i]);
}
}
- GLTFAccessorIndex _encode_accessor_as_vec3(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_vec3(Ref<GLTFState> p_state,
const Vector<Vector3> p_attribs,
const bool p_for_vertex);
- GLTFAccessorIndex _encode_accessor_as_color(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_color(Ref<GLTFState> p_state,
const Vector<Color> p_attribs,
const bool p_for_vertex);
void _calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min);
- GLTFAccessorIndex _encode_accessor_as_ints(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_ints(Ref<GLTFState> p_state,
const Vector<int32_t> p_attribs,
const bool p_for_vertex);
- GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> state,
+ GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> p_state,
const Vector<Transform3D> p_attribs,
const bool p_for_vertex);
- Error _encode_buffer_view(Ref<GLTFState> state, const double *src,
- const int count, const GLTFType type,
- const int component_type, const bool normalized,
- const int byte_offset, const bool for_vertex,
+ Error _encode_buffer_view(Ref<GLTFState> p_state, const double *p_src,
+ const int p_count, const GLTFType p_type,
+ const int p_component_type, const bool p_normalized,
+ const int p_byte_offset, const bool p_for_vertex,
GLTFBufferViewIndex &r_accessor);
- Error _encode_accessors(Ref<GLTFState> state);
- Error _encode_buffer_views(Ref<GLTFState> state);
- Error _serialize_materials(Ref<GLTFState> state);
- Error _serialize_meshes(Ref<GLTFState> state);
- Error _serialize_nodes(Ref<GLTFState> state);
- Error _serialize_scenes(Ref<GLTFState> state);
+ Error _encode_accessors(Ref<GLTFState> p_state);
+ Error _encode_buffer_views(Ref<GLTFState> p_state);
+ Error _serialize_materials(Ref<GLTFState> p_state);
+ Error _serialize_meshes(Ref<GLTFState> p_state);
+ Error _serialize_nodes(Ref<GLTFState> p_state);
+ Error _serialize_scenes(Ref<GLTFState> p_state);
String interpolation_to_string(const GLTFAnimation::Interpolation p_interp);
- GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state,
+ GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> p_state,
GLTFAnimation::Track p_track,
Ref<Animation> p_animation,
int32_t p_track_i,
GLTFNodeIndex p_node_i);
- Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path);
- Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path);
- PackedByteArray _serialize_glb_buffer(Ref<GLTFState> state, Error *r_err);
+ Error _encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path);
+ Error _encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path);
+ PackedByteArray _serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err);
Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material);
Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material);
- Error _serialize_version(Ref<GLTFState> state);
- Error _serialize_file(Ref<GLTFState> state, const String p_path);
- Error _serialize_gltf_extensions(Ref<GLTFState> state) const;
+ Error _serialize_version(Ref<GLTFState> p_state);
+ Error _serialize_file(Ref<GLTFState> p_state, const String p_path);
+ Error _serialize_gltf_extensions(Ref<GLTFState> p_state) const;
public:
// https://www.itu.int/rec/R-REC-BT.601
@@ -285,8 +278,8 @@ public:
private:
// https://github.com/microsoft/glTF-SDK/blob/master/GLTFSDK/Source/PBRUtils.cpp#L9
// https://bghgary.github.io/glTF/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
- static float solve_metallic(float p_dielectric_specular, float diffuse,
- float specular,
+ static float solve_metallic(float p_dielectric_specular, float p_diffuse,
+ float p_specular,
float p_one_minus_specular_strength);
static float get_perceived_brightness(const Color p_color);
static float get_max_component(const Color &p_color);
@@ -297,78 +290,78 @@ public:
Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0);
public:
- Node *generate_scene(Ref<GLTFState> state, float p_bake_fps = 30.0f, bool p_trimming = false);
- PackedByteArray generate_buffer(Ref<GLTFState> state);
- Error write_to_filesystem(Ref<GLTFState> state, const String &p_path);
+ Node *generate_scene(Ref<GLTFState> p_state, float p_bake_fps = 30.0f, bool p_trimming = false);
+ PackedByteArray generate_buffer(Ref<GLTFState> p_state);
+ Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path);
public:
- Error _parse_gltf_state(Ref<GLTFState> state, const String &p_search_path);
- Error _parse_gltf_extensions(Ref<GLTFState> state);
- void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root);
- void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent,
- Node3D *scene_root,
- const GLTFNodeIndex node_index);
- void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);
- void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
- const GLTFAnimationIndex index, const float bake_fps, const bool trimming);
- void _convert_mesh_instances(Ref<GLTFState> state);
- GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera3D *p_camera);
- void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node);
- GLTFLightIndex _convert_light(Ref<GLTFState> state, Light3D *p_light);
- void _convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node);
- void _convert_scene_node(Ref<GLTFState> state, Node *p_current,
+ Error _parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path);
+ Error _parse_gltf_extensions(Ref<GLTFState> p_state);
+ void _process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene_root);
+ void _generate_scene_node(Ref<GLTFState> p_state, Node *p_scene_parent,
+ Node3D *p_scene_root,
+ const GLTFNodeIndex p_node_index);
+ void _generate_skeleton_bone_node(Ref<GLTFState> p_state, Node *p_scene_parent, Node3D *p_scene_root, const GLTFNodeIndex p_node_index);
+ void _import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player,
+ const GLTFAnimationIndex p_index, const float p_bake_fps, const bool p_trimming);
+ void _convert_mesh_instances(Ref<GLTFState> p_state);
+ GLTFCameraIndex _convert_camera(Ref<GLTFState> p_state, Camera3D *p_camera);
+ void _convert_light_to_gltf(Light3D *p_light, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node);
+ GLTFLightIndex _convert_light(Ref<GLTFState> p_state, Light3D *p_light);
+ void _convert_spatial(Ref<GLTFState> p_state, Node3D *p_spatial, Ref<GLTFNode> p_node);
+ void _convert_scene_node(Ref<GLTFState> p_state, Node *p_current,
const GLTFNodeIndex p_gltf_current,
const GLTFNodeIndex p_gltf_root);
#ifdef MODULE_CSG_ENABLED
- void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
+ void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state);
#endif // MODULE_CSG_ENABLED
- void _create_gltf_node(Ref<GLTFState> state,
+ void _create_gltf_node(Ref<GLTFState> p_state,
Node *p_scene_parent,
- GLTFNodeIndex current_node_i,
+ GLTFNodeIndex p_current_node_i,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_gltf_node,
- Ref<GLTFNode> gltf_node);
+ Ref<GLTFNode> p_gltf_node);
void _convert_animation_player_to_gltf(
- AnimationPlayer *animation_player, Ref<GLTFState> state,
+ AnimationPlayer *p_animation_player, Ref<GLTFState> p_state,
GLTFNodeIndex p_gltf_current,
GLTFNodeIndex p_gltf_root_index,
Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
- void _check_visibility(Node *p_node, bool &retflag);
- void _convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state,
- Ref<GLTFNode> gltf_node);
+ void _check_visibility(Node *p_node, bool &r_retflag);
+ void _convert_camera_to_gltf(Camera3D *p_camera, Ref<GLTFState> p_state,
+ Ref<GLTFNode> p_gltf_node);
#ifdef MODULE_GRIDMAP_ENABLED
void _convert_grid_map_to_gltf(
GridMap *p_grid_map,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_node_index,
- Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
+ Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state);
#endif // MODULE_GRIDMAP_ENABLED
void _convert_multi_mesh_instance_to_gltf(
MultiMeshInstance3D *p_multi_mesh_instance,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_node_index,
- Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
+ Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state);
void _convert_skeleton_to_gltf(
- Skeleton3D *p_scene_parent, Ref<GLTFState> state,
+ Skeleton3D *p_scene_parent, Ref<GLTFState> p_state,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_node_index,
- Ref<GLTFNode> gltf_node);
+ Ref<GLTFNode> p_gltf_node);
void _convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment,
- Ref<GLTFState> state,
+ Ref<GLTFState> p_state,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_node_index,
- Ref<GLTFNode> gltf_node);
+ Ref<GLTFNode> p_gltf_node);
void _convert_mesh_instance_to_gltf(MeshInstance3D *p_mesh_instance,
- Ref<GLTFState> state,
- Ref<GLTFNode> gltf_node);
- GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> state,
+ Ref<GLTFState> p_state,
+ Ref<GLTFNode> p_gltf_node);
+ GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> p_state,
MeshInstance3D *p_mesh_instance);
- void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
+ void _convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player,
String p_animation_track_name);
- Error _serialize(Ref<GLTFState> state, const String &p_path);
- Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f);
+ Error _serialize(Ref<GLTFState> p_state, const String &p_path);
+ Error _parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file);
};
#endif // GLTF_DOCUMENT_H
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 6654c9e5d2..9f6cb20935 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -30,6 +30,8 @@
#include "gltf_state.h"
+#include "gltf_template_convert.h"
+
void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension);
ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 1c20520b22..e264da69e0 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -32,7 +32,6 @@
#define GLTF_STATE_H
#include "extensions/gltf_light.h"
-#include "gltf_template_convert.h"
#include "structures/gltf_accessor.h"
#include "structures/gltf_animation.h"
#include "structures/gltf_buffer_view.h"
@@ -44,10 +43,6 @@
#include "structures/gltf_texture.h"
#include "structures/gltf_texture_sampler.h"
-#include "core/templates/rb_map.h"
-#include "scene/animation/animation_player.h"
-#include "scene/resources/texture.h"
-
class GLTFState : public Resource {
GDCLASS(GLTFState, Resource);
friend class GLTFDocument;
@@ -194,21 +189,6 @@ public:
Variant get_additional_data(const StringName &p_extension_name);
void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
-
- //void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) {
- // this->scene_nodes = p_scene_nodes;
- //}
-
- //void set_animation_players(Vector<AnimationPlayer *> p_animation_players) {
- // this->animation_players = p_animation_players;
- //}
-
- //RBMap<Ref<Material>, GLTFMaterialIndex> get_material_cache() {
- // return this->material_cache;
- //}
- //void set_material_cache(RBMap<Ref<Material>, GLTFMaterialIndex> p_material_cache) {
- // this->material_cache = p_material_cache;
- //}
};
#endif // GLTF_STATE_H
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index a7abf256ce..cd7a23fbb2 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -30,23 +30,9 @@
#include "register_types.h"
-#ifndef _3D_DISABLED
-
#include "extensions/gltf_document_extension_convert_importer_mesh.h"
-#include "extensions/gltf_light.h"
#include "extensions/gltf_spec_gloss.h"
#include "gltf_document.h"
-#include "gltf_state.h"
-#include "structures/gltf_accessor.h"
-#include "structures/gltf_animation.h"
-#include "structures/gltf_buffer_view.h"
-#include "structures/gltf_camera.h"
-#include "structures/gltf_mesh.h"
-#include "structures/gltf_node.h"
-#include "structures/gltf_skeleton.h"
-#include "structures/gltf_skin.h"
-#include "structures/gltf_texture.h"
-#include "structures/gltf_texture_sampler.h"
#ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
@@ -172,5 +158,3 @@ void uninitialize_gltf_module(ModuleInitializationLevel p_level) {
}
GLTFDocument::unregister_all_gltf_document_extensions();
}
-
-#endif // _3D_DISABLED
diff --git a/modules/gltf/structures/gltf_accessor.h b/modules/gltf/structures/gltf_accessor.h
index bfb71d57fe..8e4bb2d3f9 100644
--- a/modules/gltf/structures/gltf_accessor.h
+++ b/modules/gltf/structures/gltf_accessor.h
@@ -31,9 +31,8 @@
#ifndef GLTF_ACCESSOR_H
#define GLTF_ACCESSOR_H
-#include "core/io/resource.h"
-
#include "../gltf_defines.h"
+#include "core/io/resource.h"
struct GLTFAccessor : public Resource {
GDCLASS(GLTFAccessor, Resource);
diff --git a/modules/gltf/structures/gltf_animation.h b/modules/gltf/structures/gltf_animation.h
index 3777f579f6..fc535631bb 100644
--- a/modules/gltf/structures/gltf_animation.h
+++ b/modules/gltf/structures/gltf_animation.h
@@ -31,7 +31,7 @@
#ifndef GLTF_ANIMATION_H
#define GLTF_ANIMATION_H
-#include "core/io/resource.h"
+#include "scene/animation/animation_player.h"
class GLTFAnimation : public Resource {
GDCLASS(GLTFAnimation, Resource);
diff --git a/modules/gltf/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp
index 212b9b80c8..7a5ab2763c 100644
--- a/modules/gltf/structures/gltf_camera.cpp
+++ b/modules/gltf/structures/gltf_camera.cpp
@@ -30,6 +30,8 @@
#include "gltf_camera.h"
+#include "scene/3d/camera_3d.h"
+
void GLTFCamera::_bind_methods() {
ClassDB::bind_static_method("GLTFCamera", D_METHOD("from_node", "camera_node"), &GLTFCamera::from_node);
ClassDB::bind_method(D_METHOD("to_node"), &GLTFCamera::to_node);
diff --git a/modules/gltf/structures/gltf_camera.h b/modules/gltf/structures/gltf_camera.h
index 50ae10e17a..5e8a1da5f7 100644
--- a/modules/gltf/structures/gltf_camera.h
+++ b/modules/gltf/structures/gltf_camera.h
@@ -32,7 +32,8 @@
#define GLTF_CAMERA_H
#include "core/io/resource.h"
-#include "scene/3d/camera_3d.h"
+
+class Camera3D;
// Reference and test file:
// https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md
@@ -64,7 +65,7 @@ public:
real_t get_depth_near() const { return depth_near; }
void set_depth_near(real_t p_val) { depth_near = p_val; }
- static Ref<GLTFCamera> from_node(const Camera3D *p_light);
+ static Ref<GLTFCamera> from_node(const Camera3D *p_camera);
Camera3D *to_node() const;
static Ref<GLTFCamera> from_dictionary(const Dictionary p_dictionary);
diff --git a/modules/gltf/structures/gltf_mesh.h b/modules/gltf/structures/gltf_mesh.h
index 2fa37fd727..92722ce75c 100644
--- a/modules/gltf/structures/gltf_mesh.h
+++ b/modules/gltf/structures/gltf_mesh.h
@@ -31,10 +31,8 @@
#ifndef GLTF_MESH_H
#define GLTF_MESH_H
-#include "core/io/resource.h"
-#include "scene/3d/importer_mesh_instance_3d.h"
+#include "../gltf_defines.h"
#include "scene/resources/importer_mesh.h"
-#include "scene/resources/mesh.h"
class GLTFMesh : public Resource {
GDCLASS(GLTFMesh, Resource);
diff --git a/modules/gltf/structures/gltf_texture_sampler.h b/modules/gltf/structures/gltf_texture_sampler.h
index 3fad31bbee..7bb7cd62e3 100644
--- a/modules/gltf/structures/gltf_texture_sampler.h
+++ b/modules/gltf/structures/gltf_texture_sampler.h
@@ -31,7 +31,6 @@
#ifndef GLTF_TEXTURE_SAMPLER_H
#define GLTF_TEXTURE_SAMPLER_H
-#include "core/io/resource.h"
#include "scene/resources/material.h"
class GLTFTextureSampler : public Resource {
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index de50e9ea1e..06ad806afc 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -656,6 +656,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
if (bake_navigation) {
RID region = NavigationServer3D::get_singleton()->region_create();
+ NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, navmesh);
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform);
@@ -779,6 +780,7 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F.key].item);
if (nm.is_valid()) {
RID region = NavigationServer3D::get_singleton()->region_create();
+ NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, nm);
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F.value.xform);
diff --git a/modules/mono/README.md b/modules/mono/README.md
index 366777cfc1..74b4531dfb 100644
--- a/modules/mono/README.md
+++ b/modules/mono/README.md
@@ -46,10 +46,10 @@ C# solutions during development to avoid mistakes.
# Double Precision Support (REAL_T_IS_DOUBLE)
-Follow the above instructions but build Godot with the float=64 argument to scons
+Follow the above instructions but build Godot with the precision=double argument to scons
-When building the NuGet packages, specify `--float=64` - for example:
+When building the NuGet packages, specify `--precision=double` - for example:
```sh
./modules/mono/build_scripts/build_assemblies.py --godot-output-dir ./bin \
- --push-nupkgs-local ~/MyLocalNugetSource --float=64
+ --push-nupkgs-local ~/MyLocalNugetSource --precision=double
```
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index 7343af0b39..0b91cda9b8 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -193,7 +193,7 @@ def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: Optional[List[str]
return subprocess.call(args, env=msbuild_env)
-def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size):
+def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, precision):
target_filenames = [
"GodotSharp.dll",
"GodotSharp.pdb",
@@ -214,7 +214,7 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, flo
args = ["/restore", "/t:Build", "/p:Configuration=" + build_config, "/p:NoWarn=1591"]
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
- if float_size == "64":
+ if precision == "double":
args += ["/p:GodotFloat64=true"]
sln = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
@@ -303,12 +303,12 @@ def generate_sdk_package_versions():
f.close()
-def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, float_size):
+def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, precision):
# Generate SdkPackageVersions.props
generate_sdk_package_versions()
# Godot API
- exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size)
+ exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, precision)
if exit_code != 0:
return exit_code
@@ -319,7 +319,7 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p
)
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
- if float_size == "64":
+ if precision == "double":
args += ["/p:GodotFloat64=true"]
exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
if exit_code != 0:
@@ -329,7 +329,7 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p
args = ["/restore", "/t:Build", "/p:Configuration=Release"]
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
- if float_size == "64":
+ if precision == "double":
args += ["/p:GodotFloat64=true"]
sln = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
@@ -354,7 +354,9 @@ def main():
parser.add_argument("--godot-platform", type=str, default="")
parser.add_argument("--mono-prefix", type=str, default="")
parser.add_argument("--push-nupkgs-local", type=str, default="")
- parser.add_argument("--float", type=str, default="32", choices=["32", "64"], help="Floating-point precision")
+ parser.add_argument(
+ "--precision", type=str, default="single", choices=["single", "double"], help="Floating-point precision level"
+ )
args = parser.parse_args()
@@ -378,7 +380,7 @@ def main():
args.godot_platform,
args.dev_debug,
push_nupkgs_local,
- args.float,
+ args.precision,
)
sys.exit(exit_code)
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 137fd61a25..d0f52488bb 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -73,7 +73,7 @@ static bool _create_project_solution_if_needed() {
CSharpLanguage *CSharpLanguage::singleton = nullptr;
-GDNativeInstanceBindingCallbacks CSharpLanguage::_instance_binding_callbacks = {
+GDExtensionInstanceBindingCallbacks CSharpLanguage::_instance_binding_callbacks = {
&_instance_binding_create_callback,
&_instance_binding_free_callback,
&_instance_binding_reference_callback
@@ -1293,7 +1293,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
}
}
-GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) {
+GDExtensionBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDExtensionBool p_reference) {
CRASH_COND(!p_binding);
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
@@ -2202,7 +2202,7 @@ void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) {
void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
bool tool = false;
- // TODO: Use GDNative godot_dictionary
+ // TODO: Use GDExtension godot_dictionary
Array methods_array;
methods_array.~Array();
Dictionary rpc_functions_dict;
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index e5e53acb07..68d374d262 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -352,9 +352,9 @@ class CSharpLanguage : public ScriptLanguage {
static void *_instance_binding_create_callback(void *p_token, void *p_instance);
static void _instance_binding_free_callback(void *p_token, void *p_instance, void *p_binding);
- static GDNativeBool _instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference);
+ static GDExtensionBool _instance_binding_reference_callback(void *p_token, void *p_binding, GDExtensionBool p_reference);
- static GDNativeInstanceBindingCallbacks _instance_binding_callbacks;
+ static GDExtensionInstanceBindingCallbacks _instance_binding_callbacks;
public:
static void *get_instance_binding(Object *p_object);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
index 9a46b7d164..ccaba4d727 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
@@ -45,7 +45,7 @@ namespace Godot.SourceGenerators.Sample
[Export] private Color field_Color = Colors.Aquamarine;
[Export] private Plane field_Plane = Plane.PlaneXZ;
[Export] private Callable field_Callable = new Callable(Engine.GetMainLoop(), "_process");
- [Export] private SignalInfo field_SignalInfo = new SignalInfo(Engine.GetMainLoop(), "property_list_changed");
+ [Export] private Signal field_Signal = new Signal(Engine.GetMainLoop(), "property_list_changed");
// Enums
[SuppressMessage("ReSharper", "UnusedMember.Local")]
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
index eb83833b40..5afaeb736f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
@@ -91,7 +91,7 @@ namespace Godot.SourceGenerators.Sample
}
}
- // Lamda Property
+ // Lambda Property
private String _lamdaProperty_String = "LamdaProperty_String";
[Export]
public String LamdaProperty_String
@@ -133,7 +133,7 @@ namespace Godot.SourceGenerators.Sample
[Export] private Color property_Color { get; set; } = Colors.Aquamarine;
[Export] private Plane property_Plane { get; set; } = Plane.PlaneXZ;
[Export] private Callable property_Callable { get; set; } = new Callable(Engine.GetMainLoop(), "_process");
- [Export] private SignalInfo property_SignalInfo { get; set; } = new SignalInfo(Engine.GetMainLoop(), "property_list_changed");
+ [Export] private Signal property_Signal { get; set; } = new Signal(Engine.GetMainLoop(), "property_list_changed");
// Enums
[SuppressMessage("ReSharper", "UnusedMember.Local")]
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
index 15f5803bf0..ee1374d0b9 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
@@ -37,7 +37,7 @@ namespace Godot.SourceGenerators
Color,
Plane,
Callable,
- SignalInfo,
+ Signal,
// Enums
Enum,
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index 5b3f677f87..8b2f96036b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -56,7 +56,7 @@ namespace Godot.SourceGenerators
MarshalType.Color => VariantType.Color,
MarshalType.Plane => VariantType.Plane,
MarshalType.Callable => VariantType.Callable,
- MarshalType.SignalInfo => VariantType.Signal,
+ MarshalType.Signal => VariantType.Signal,
MarshalType.Enum => VariantType.Int,
MarshalType.ByteArray => VariantType.PackedByteArray,
MarshalType.Int32Array => VariantType.PackedInt32Array,
@@ -147,7 +147,7 @@ namespace Godot.SourceGenerators
{ Name: "Plane" } => MarshalType.Plane,
{ Name: "RID" } => MarshalType.RID,
{ Name: "Callable" } => MarshalType.Callable,
- { Name: "SignalInfo" } => MarshalType.SignalInfo,
+ { Name: "Signal" } => MarshalType.Signal,
{ Name: "Variant" } => MarshalType.Variant,
_ => null
};
@@ -304,7 +304,12 @@ namespace Godot.SourceGenerators
{
return marshalType switch
{
- // For generic Godot collections, VariantUtils.ConvertTo<T> is slower, so we need this special case
+ // We need a special case for GodotObjectOrDerived[], because it's not supported by VariantUtils.ConvertTo<T>
+ MarshalType.GodotObjectOrDerivedArray =>
+ source.Append(VariantUtils, ".ConvertToSystemArrayOfGodotObject<",
+ ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedNameIncludeGlobal(), ">(",
+ inputExpr, ")"),
+ // We need a special case for generic Godot collections and GodotObjectOrDerived[], because VariantUtils.ConvertTo<T> is slower
MarshalType.GodotGenericDictionary =>
source.Append(VariantUtils, ".ConvertToDictionaryObject<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
@@ -324,7 +329,10 @@ namespace Godot.SourceGenerators
{
return marshalType switch
{
- // For generic Godot collections, VariantUtils.CreateFrom<T> is slower, so we need this special case
+ // We need a special case for GodotObjectOrDerived[], because it's not supported by VariantUtils.CreateFrom<T>
+ MarshalType.GodotObjectOrDerivedArray =>
+ source.Append(VariantUtils, ".CreateFromSystemArrayOfGodotObject(", inputExpr, ")"),
+ // We need a special case for generic Godot collections and GodotObjectOrDerived[], because VariantUtils.CreateFrom<T> is slower
MarshalType.GodotGenericDictionary =>
source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
MarshalType.GodotGenericArray =>
@@ -339,7 +347,11 @@ namespace Godot.SourceGenerators
{
return marshalType switch
{
- // For generic Godot collections, Variant.As<T> is slower, so we need this special case
+ // We need a special case for GodotObjectOrDerived[], because it's not supported by Variant.As<T>
+ MarshalType.GodotObjectOrDerivedArray =>
+ source.Append(inputExpr, ".AsGodotObjectArray<",
+ ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedNameIncludeGlobal(), ">()"),
+ // We need a special case for generic Godot collections and GodotObjectOrDerived[], because Variant.As<T> is slower
MarshalType.GodotGenericDictionary =>
source.Append(inputExpr, ".AsGodotDictionary<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
@@ -357,7 +369,10 @@ namespace Godot.SourceGenerators
{
return marshalType switch
{
- // For generic Godot collections, Variant.From<T> is slower, so we need this special case
+ // We need a special case for GodotObjectOrDerived[], because it's not supported by Variant.From<T>
+ MarshalType.GodotObjectOrDerivedArray =>
+ source.Append("global::Godot.Variant.CreateFrom(", inputExpr, ")"),
+ // We need a special case for generic Godot collections, because Variant.From<T> is slower
MarshalType.GodotGenericDictionary or MarshalType.GodotGenericArray =>
source.Append("global::Godot.Variant.CreateFrom(", inputExpr, ")"),
_ => source.Append("global::Godot.Variant.From<",
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 9f0bc3fbe3..6559cbf75d 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2489,9 +2489,12 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
if (!ret_void) {
if (return_type->cname != name_cache.type_Variant) {
+ // Usually the return value takes ownership, but in this case the variant is only used
+ // for conversion to another return type. As such, the local variable takes ownership.
r_output << "using godot_variant " << C_LOCAL_VARARG_RET " = ";
} else {
- r_output << "using godot_variant " << C_LOCAL_RET " = ";
+ // Variant's [c_out] takes ownership of the variant value
+ r_output << "godot_variant " << C_LOCAL_RET " = ";
}
}
@@ -3651,7 +3654,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_type = itype.proxy_name;
itype.cs_in_expr = "%0";
itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(in %1);\n";
- itype.c_out = "%5return " C_METHOD_MANAGED_FROM_SIGNAL "(&%1);\n";
+ itype.c_out = "%5return " C_METHOD_MANAGED_FROM_SIGNAL "(in %1);\n";
itype.c_arg_in = "&%s_in";
itype.c_type = "godot_signal";
itype.c_type_in = "in " + itype.cs_type;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
index ba65b61e95..65f33e43a8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
@@ -1,7 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=alcs/@EntryIndexedValue">True</s:Boolean>
- <s:Boolean x:Key="/Default/UserDictionary/Words/=gdnative/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=gdextension/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=godotsharp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=icall/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quat/@EntryIndexedValue">True</s:Boolean>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
index b7d633517a..acdae83d2e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -1,20 +1,32 @@
using System;
+using System.Diagnostics.CodeAnalysis;
#nullable enable
namespace Godot
{
/// <summary>
- /// An attribute that determines if an assembly has scripts. If so, what types of scripts the assembly has.
+ /// Attribute that determines that the assembly contains Godot scripts and, optionally, the
+ /// collection of types that implement scripts; otherwise, retrieving the types requires lookup.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyHasScriptsAttribute : Attribute
{
+ /// <summary>
+ /// If the Godot scripts contained in the assembly require lookup
+ /// and can't rely on <see cref="ScriptTypes"/>.
+ /// </summary>
+ [MemberNotNullWhen(false, nameof(ScriptTypes))]
public bool RequiresLookup { get; }
+
+ /// <summary>
+ /// The collection of types that implement a Godot script.
+ /// </summary>
public Type[]? ScriptTypes { get; }
/// <summary>
- /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// Constructs a new AssemblyHasScriptsAttribute instance
+ /// that requires lookup to get the Godot scripts.
/// </summary>
public AssemblyHasScriptsAttribute()
{
@@ -23,9 +35,10 @@ namespace Godot
}
/// <summary>
- /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// Constructs a new AssemblyHasScriptsAttribute instance
+ /// that includes the Godot script types and requires no lookup.
/// </summary>
- /// <param name="scriptTypes">The specified type(s) of scripts.</param>
+ /// <param name="scriptTypes">The collection of types that implement a Godot script.</param>
public AssemblyHasScriptsAttribute(Type[] scriptTypes)
{
RequiresLookup = false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
index 3d204bdf9f..a48d79091f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -3,23 +3,30 @@ using System;
namespace Godot
{
/// <summary>
- /// An attribute used to export objects.
+ /// Exports the annotated member as a property of the Godot Object.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportAttribute : Attribute
{
- private PropertyHint hint;
- private string hintString;
+ /// <summary>
+ /// Optional hint that determines how the property should be handled by the editor.
+ /// </summary>
+ public PropertyHint Hint { get; }
+
+ /// <summary>
+ /// Optional string that can contain additional metadata for the <see cref="Hint"/>.
+ /// </summary>
+ public string HintString { get; }
/// <summary>
/// Constructs a new ExportAttribute Instance.
/// </summary>
- /// <param name="hint">A hint to the exported object.</param>
- /// <param name="hintString">A string representing the exported object.</param>
+ /// <param name="hint">The hint for the exported property.</param>
+ /// <param name="hintString">A string that may contain additional metadata for the hint.</param>
public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
{
- this.hint = hint;
- this.hintString = hintString;
+ Hint = hint;
+ HintString = hintString;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
index 101e56f8d3..2ae55acd3e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
@@ -8,7 +8,10 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportCategoryAttribute : Attribute
{
- private string name;
+ /// <summary>
+ /// Name of the category.
+ /// </summary>
+ public string Name { get; }
/// <summary>
/// Define a new category for the following exported properties.
@@ -16,7 +19,7 @@ namespace Godot
/// <param name="name">The name of the category.</param>
public ExportCategoryAttribute(string name)
{
- this.name = name;
+ Name = name;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
index 3bd532cec1..82bd446640 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
@@ -1,5 +1,7 @@
using System;
+#nullable enable
+
namespace Godot
{
/// <summary>
@@ -8,8 +10,15 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportGroupAttribute : Attribute
{
- private string name;
- private string prefix;
+ /// <summary>
+ /// Name of the group.
+ /// </summary>
+ public string Name { get; }
+
+ /// <summary>
+ /// If provided, the prefix that all properties must have to be considered part of the group.
+ /// </summary>
+ public string? Prefix { get; }
/// <summary>
/// Define a new group for the following exported properties.
@@ -18,8 +27,8 @@ namespace Godot
/// <param name="prefix">If provided, the group would make group to only consider properties that have this prefix.</param>
public ExportGroupAttribute(string name, string prefix = "")
{
- this.name = name;
- this.prefix = prefix;
+ Name = name;
+ Prefix = prefix;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
index 2ae6eb0b68..3282b466f6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
@@ -1,5 +1,7 @@
using System;
+#nullable enable
+
namespace Godot
{
/// <summary>
@@ -8,8 +10,15 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportSubgroupAttribute : Attribute
{
- private string name;
- private string prefix;
+ /// <summary>
+ /// Name of the subgroup.
+ /// </summary>
+ public string Name { get; }
+
+ /// <summary>
+ /// If provided, the prefix that all properties must have to be considered part of the subgroup.
+ /// </summary>
+ public string? Prefix { get; }
/// <summary>
/// Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock.
@@ -18,8 +27,8 @@ namespace Godot
/// <param name="prefix">If provided, the subgroup would make group to only consider properties that have this prefix.</param>
public ExportSubgroupAttribute(string name, string prefix = "")
{
- this.name = name;
- this.prefix = prefix;
+ Name = name;
+ Prefix = prefix;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs
index fb37838ffa..afee926464 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs
@@ -19,17 +19,17 @@ namespace Godot
/// <summary>
/// If the method will also be called locally; otherwise, it is only called remotely.
/// </summary>
- public bool CallLocal { get; set; } = false;
+ public bool CallLocal { get; init; } = false;
/// <summary>
/// Transfer mode for the annotated method.
/// </summary>
- public MultiplayerPeer.TransferModeEnum TransferMode { get; set; } = MultiplayerPeer.TransferModeEnum.Reliable;
+ public MultiplayerPeer.TransferModeEnum TransferMode { get; init; } = MultiplayerPeer.TransferModeEnum.Reliable;
/// <summary>
/// Transfer channel for the annotated mode.
/// </summary>
- public int TransferChannel { get; set; } = 0;
+ public int TransferChannel { get; init; } = 0;
/// <summary>
/// Constructs a <see cref="RPCAttribute"/> instance.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
index 2c8a53ae1c..f05bcdac38 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -8,6 +8,9 @@ namespace Godot
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ScriptPathAttribute : Attribute
{
+ /// <summary>
+ /// File path to the script.
+ /// </summary>
public string Path { get; }
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index a3cfecfaa6..d94fbff331 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -613,8 +613,8 @@ namespace Godot
return VariantUtils.CreateFrom(plane);
case Callable callable:
return VariantUtils.CreateFrom(callable);
- case SignalInfo signalInfo:
- return VariantUtils.CreateFrom(signalInfo);
+ case Signal signal:
+ return VariantUtils.CreateFrom(signal);
case string @string:
return VariantUtils.CreateFrom(@string);
case byte[] byteArray:
@@ -705,7 +705,7 @@ namespace Godot
[typeof(Color)] = (in godot_variant variant) => VariantUtils.ConvertTo<Color>(variant),
[typeof(Plane)] = (in godot_variant variant) => VariantUtils.ConvertTo<Plane>(variant),
[typeof(Callable)] = (in godot_variant variant) => VariantUtils.ConvertTo<Callable>(variant),
- [typeof(SignalInfo)] = (in godot_variant variant) => VariantUtils.ConvertTo<SignalInfo>(variant),
+ [typeof(Signal)] = (in godot_variant variant) => VariantUtils.ConvertTo<Signal>(variant),
[typeof(string)] = (in godot_variant variant) => VariantUtils.ConvertTo<string>(variant),
[typeof(byte[])] = (in godot_variant variant) => VariantUtils.ConvertTo<byte[]>(variant),
[typeof(int[])] = (in godot_variant variant) => VariantUtils.ConvertTo<int[]>(variant),
@@ -739,6 +739,26 @@ namespace Godot
if (typeof(Godot.Object).IsAssignableFrom(type))
return Convert.ChangeType(VariantUtils.ConvertTo<Godot.Object>(variant), type);
+ if (typeof(Godot.Object[]).IsAssignableFrom(type))
+ {
+ static Godot.Object[] ConvertToSystemArrayOfGodotObject(in godot_array nativeArray, Type type)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(nativeArray));
+
+ int length = array.Count;
+ var ret = (Godot.Object[])Activator.CreateInstance(type, length)!;
+
+ for (int i = 0; i < length; i++)
+ ret[i] = array[i].AsGodotObject();
+
+ return ret;
+ }
+
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant);
+ return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type);
+ }
+
if (type.IsEnum)
{
var enumUnderlyingType = type.GetEnumUnderlyingType();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index 6176093bc1..0d9a698af0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -99,7 +99,7 @@ namespace Godot.NativeInterop
if (type == typeof(Callable))
return Variant.Type.Callable;
- if (type == typeof(SignalInfo))
+ if (type == typeof(Signal))
return Variant.Type.Signal;
if (type.IsEnum)
@@ -288,9 +288,9 @@ namespace Godot.NativeInterop
return new Callable();
}
- // SignalInfo
+ // Signal
- public static godot_signal ConvertSignalToNative(in SignalInfo p_managed_signal)
+ public static godot_signal ConvertSignalToNative(in Signal p_managed_signal)
{
ulong ownerId = p_managed_signal.Owner.GetInstanceId();
godot_string_name name;
@@ -308,12 +308,12 @@ namespace Godot.NativeInterop
return new godot_signal(name, ownerId);
}
- public static SignalInfo ConvertSignalToManaged(in godot_signal p_signal)
+ public static Signal ConvertSignalToManaged(in godot_signal p_signal)
{
var owner = GD.InstanceFromId(p_signal.ObjectId);
var name = StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(p_signal.Name));
- return new SignalInfo(owner, name);
+ return new Signal(owner, name);
}
// Array
@@ -333,22 +333,6 @@ namespace Godot.NativeInterop
return ret;
}
- // TODO: This needs reflection. Look for an alternative.
- internal static Godot.Object[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(in godot_array p_array,
- Type type)
- {
- var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_array_new_copy(p_array));
-
- int length = array.Count;
- var ret = (Godot.Object[])Activator.CreateInstance(type, length)!;
-
- for (int i = 0; i < length; i++)
- ret[i] = array[i].AsGodotObject();
-
- return ret;
- }
-
internal static StringName[] ConvertNativeGodotArrayToSystemArrayOfStringName(in godot_array p_array)
{
var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index ba8e7a6c65..6a4717f2c3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -102,7 +102,7 @@ namespace Godot.NativeInterop
=> new() { Type = Variant.Type.Signal, Signal = from };
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_variant CreateFromSignalInfo(SignalInfo from)
+ public static godot_variant CreateFromSignal(Signal from)
=> CreateFromSignalTakingOwnershipOfDisposableValue(
Marshaling.ConvertSignalToNative(from));
@@ -486,7 +486,7 @@ namespace Godot.NativeInterop
=> NativeFuncs.godotsharp_variant_as_signal(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static SignalInfo ConvertToSignalInfo(in godot_variant p_var)
+ public static Signal ConvertToSignalManaged(in godot_variant p_var)
=> Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var));
public static godot_array ConvertToArray(in godot_variant p_var)
@@ -594,12 +594,5 @@ namespace Godot.NativeInterop
using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(godotArray);
}
-
- // ReSharper disable once RedundantNameQualifier
- public static Godot.Object[] ConvertToSystemArrayOfGodotObject(in godot_variant p_var, Type type)
- {
- using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
- return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(godotArray, type);
- }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
index 80ef2a1ea1..9a3ed85e66 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
@@ -125,8 +125,8 @@ public partial class VariantUtils
if (typeof(T) == typeof(Callable))
return CreateFromCallable(UnsafeAs<Callable>(from));
- if (typeof(T) == typeof(SignalInfo))
- return CreateFromSignalInfo(UnsafeAs<SignalInfo>(from));
+ if (typeof(T) == typeof(Signal))
+ return CreateFromSignal(UnsafeAs<Signal>(from));
if (typeof(T) == typeof(string))
return CreateFromString(UnsafeAs<string>(from));
@@ -311,8 +311,8 @@ public partial class VariantUtils
if (typeof(T) == typeof(Callable))
return UnsafeAsT(ConvertToCallableManaged(variant));
- if (typeof(T) == typeof(SignalInfo))
- return UnsafeAsT(ConvertToSignalInfo(variant));
+ if (typeof(T) == typeof(Signal))
+ return UnsafeAsT(ConvertToSignalManaged(variant));
if (typeof(T) == typeof(string))
return UnsafeAsT(ConvertToStringObject(variant));
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index 8b1b73fcc3..fd37f8d9e8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -652,7 +652,7 @@ namespace Godot
/// added to the first and second values of the final column respectively.
/// </summary>
/// <param name="offset">The offset to apply to the projection.</param>
- /// <returns>The offseted projection.</returns>
+ /// <returns>The offsetted projection.</returns>
public readonly Projection JitterOffseted(Vector2 offset)
{
Projection proj = this;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Signal.cs
index 3f50df0a0d..f9b8f06603 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Signal.cs
@@ -3,7 +3,7 @@ namespace Godot
/// <summary>
/// Represents a signal defined in an object.
/// </summary>
- public readonly struct SignalInfo
+ public readonly struct Signal : IAwaitable<Variant[]>
{
private readonly Object _owner;
private readonly StringName _signalName;
@@ -18,15 +18,20 @@ namespace Godot
public StringName Name => _signalName;
/// <summary>
- /// Creates a new <see cref="SignalInfo"/> with the name <paramref name="name"/>
+ /// Creates a new <see cref="Signal"/> with the name <paramref name="name"/>
/// in the specified <paramref name="owner"/>.
/// </summary>
/// <param name="owner">Object that contains the signal.</param>
/// <param name="name">Name of the signal.</param>
- public SignalInfo(Object owner, StringName name)
+ public Signal(Object owner, StringName name)
{
_owner = owner;
_signalName = name;
}
+
+ public IAwaiter<Variant[]> GetAwaiter()
+ {
+ return new SignalAwaiter(_owner, _signalName, _owner);
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
index 49a363cef2..c4c53a39f9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
@@ -137,7 +137,7 @@ public partial struct Variant : IDisposable
Type.Rid => AsRID(),
Type.Object => AsGodotObject(),
Type.Callable => AsCallable(),
- Type.Signal => AsSignalInfo(),
+ Type.Signal => AsSignal(),
Type.Dictionary => AsGodotDictionary(),
Type.Array => AsGodotArray(),
Type.PackedByteArray => AsByteArray(),
@@ -283,8 +283,8 @@ public partial struct Variant : IDisposable
VariantUtils.ConvertToCallableManaged((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public SignalInfo AsSignalInfo() =>
- VariantUtils.ConvertToSignalInfo((godot_variant)NativeVar);
+ public Signal AsSignal() =>
+ VariantUtils.ConvertToSignalManaged((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte[] AsByteArray() =>
@@ -464,7 +464,7 @@ public partial struct Variant : IDisposable
public static explicit operator Callable(Variant from) => from.AsCallable();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator SignalInfo(Variant from) => from.AsSignalInfo();
+ public static explicit operator Signal(Variant from) => from.AsSignal();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator byte[](Variant from) => from.AsByteArray();
@@ -614,7 +614,7 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Callable from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(SignalInfo from) => from;
+ public static Variant CreateFrom(Signal from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Span<byte> from) => from;
@@ -804,8 +804,8 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromCallable(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(SignalInfo from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSignalInfo(from));
+ public static implicit operator Variant(Signal from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSignal(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(byte[] from) =>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 503e5abe37..644212c74d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -116,7 +116,7 @@
<Compile Include="Core\NativeInterop\NativeFuncs.cs" />
<Compile Include="Core\NativeInterop\InteropStructs.cs" />
<Compile Include="Core\NativeInterop\Marshaling.cs" />
- <Compile Include="Core\SignalInfo.cs" />
+ <Compile Include="Core\Signal.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
<Compile Include="Core\StringExtensions.cs" />
<Compile Include="Core\StringName.cs" />
diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
index 7ed6255a62..af7c345f15 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
@@ -17,7 +17,7 @@
<param index="0" name="filter" type="Callable" />
<description>
Adds a peer visibility filter for this synchronizer.
- [code]filter[/code] should take a peer id [int] and return a [bool].
+ [code]filter[/code] should take a peer ID [int] and return a [bool].
</description>
</method>
<method name="get_visibility_for" qualifiers="const">
diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp
index dbf2b3751e..a7e29dfcc7 100644
--- a/modules/multiplayer/scene_rpc_interface.cpp
+++ b/modules/multiplayer/scene_rpc_interface.cpp
@@ -82,7 +82,7 @@ void SceneRPCInterface::_parse_rpc_config(const Variant &p_config, bool p_for_no
Array names = config.keys();
names.sort(); // Ensure ID order
for (int i = 0; i < names.size(); i++) {
- ERR_CONTINUE(names[i].get_type() != Variant::STRING);
+ ERR_CONTINUE(names[i].get_type() != Variant::STRING && names[i].get_type() != Variant::STRING_NAME);
String name = names[i].operator String();
ERR_CONTINUE(config[name].get_type() != Variant::DICTIONARY);
ERR_CONTINUE(!config[name].operator Dictionary().has("rpc_mode"));
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 8ca73a3adb..e5949c935b 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -383,6 +383,20 @@ real_t GodotNavigationServer::region_get_travel_cost(RID p_region) const {
return region->get_travel_cost();
}
+COMMAND_2(region_set_owner_id, RID, p_region, ObjectID, p_owner_id) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+
+ region->set_owner_id(p_owner_id);
+}
+
+ObjectID GodotNavigationServer::region_get_owner_id(RID p_region) const {
+ const NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, ObjectID());
+
+ return region->get_owner_id();
+}
+
bool GodotNavigationServer::region_owns_point(RID p_region, const Vector3 &p_point) const {
const NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(region == nullptr, false);
@@ -570,6 +584,20 @@ real_t GodotNavigationServer::link_get_travel_cost(const RID p_link) const {
return link->get_travel_cost();
}
+COMMAND_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_owner_id(p_owner_id);
+}
+
+ObjectID GodotNavigationServer::link_get_owner_id(RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, ObjectID());
+
+ return link->get_owner_id();
+}
+
RID GodotNavigationServer::agent_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
@@ -676,14 +704,14 @@ bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const {
return agent->is_map_changed();
}
-COMMAND_4(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata) {
+COMMAND_4(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata) {
RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
- agent->set_callback(p_receiver == nullptr ? ObjectID() : p_receiver->get_instance_id(), p_method, p_udata);
+ agent->set_callback(p_object_id, p_method, p_udata);
if (agent->get_map()) {
- if (p_receiver == nullptr) {
+ if (p_object_id == ObjectID()) {
agent->get_map()->remove_agent_as_controlled(agent);
} else {
agent->get_map()->set_agent_as_controlled(agent);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index ab5e722d35..18431e39b8 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -125,6 +125,9 @@ public:
COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost);
virtual real_t region_get_travel_cost(RID p_region) const override;
+ COMMAND_2(region_set_owner_id, RID, p_region, ObjectID, p_owner_id);
+ virtual ObjectID region_get_owner_id(RID p_region) const override;
+
virtual bool region_owns_point(RID p_region, const Vector3 &p_point) const override;
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
@@ -153,6 +156,8 @@ public:
virtual real_t link_get_enter_cost(RID p_link) const override;
COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost);
virtual real_t link_get_travel_cost(RID p_link) const override;
+ COMMAND_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id);
+ virtual ObjectID link_get_owner_id(RID p_link) const override;
virtual RID agent_create() const override;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
@@ -167,7 +172,7 @@ public:
COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position);
COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore);
virtual bool agent_is_map_changed(RID p_agent) const override;
- COMMAND_4_DEF(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, Variant());
+ COMMAND_4_DEF(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata, Variant());
COMMAND_1(free, RID, p_object);
diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h
index 6dfaaf9af4..f5d2880d36 100644
--- a/modules/navigation/nav_base.h
+++ b/modules/navigation/nav_base.h
@@ -41,6 +41,7 @@ protected:
uint32_t navigation_layers = 1;
float enter_cost = 0.0;
float travel_cost = 1.0;
+ ObjectID owner_id;
public:
void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; }
@@ -51,6 +52,9 @@ public:
void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
float get_travel_cost() const { return travel_cost; }
+
+ void set_owner_id(ObjectID p_owner_id) { owner_id = p_owner_id; }
+ ObjectID get_owner_id() const { return owner_id; }
};
#endif // NAV_BASE_H
diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp
index 7e02f0374d..634f653376 100644
--- a/modules/openxr/action_map/openxr_action.cpp
+++ b/modules/openxr/action_map/openxr_action.cpp
@@ -75,6 +75,7 @@ String OpenXRAction::get_name_with_set() const {
void OpenXRAction::set_localized_name(const String p_localized_name) {
localized_name = p_localized_name;
+ emit_changed();
}
String OpenXRAction::get_localized_name() const {
@@ -83,6 +84,7 @@ String OpenXRAction::get_localized_name() const {
void OpenXRAction::set_action_type(const OpenXRAction::ActionType p_action_type) {
action_type = p_action_type;
+ emit_changed();
}
OpenXRAction::ActionType OpenXRAction::get_action_type() const {
@@ -91,6 +93,7 @@ OpenXRAction::ActionType OpenXRAction::get_action_type() const {
void OpenXRAction::set_toplevel_paths(const PackedStringArray p_toplevel_paths) {
toplevel_paths = p_toplevel_paths;
+ emit_changed();
}
PackedStringArray OpenXRAction::get_toplevel_paths() const {
@@ -100,15 +103,18 @@ PackedStringArray OpenXRAction::get_toplevel_paths() const {
void OpenXRAction::add_toplevel_path(const String p_toplevel_path) {
if (!toplevel_paths.has(p_toplevel_path)) {
toplevel_paths.push_back(p_toplevel_path);
+ emit_changed();
}
}
void OpenXRAction::rem_toplevel_path(const String p_toplevel_path) {
if (toplevel_paths.has(p_toplevel_path)) {
toplevel_paths.erase(p_toplevel_path);
+ emit_changed();
}
}
void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) {
toplevel_paths = p_toplevel_paths.split(",", false);
+ emit_changed();
}
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index 123f860ce9..226bfa18ba 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -95,6 +95,7 @@ void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {
if (action_sets.find(p_action_set) == -1) {
action_sets.push_back(p_action_set);
+ emit_changed();
}
}
@@ -102,6 +103,7 @@ void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
int idx = action_sets.find(p_action_set);
if (idx != -1) {
action_sets.remove_at(idx);
+ emit_changed();
}
}
@@ -146,6 +148,7 @@ void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_in
if (interaction_profiles.find(p_interaction_profile) == -1) {
interaction_profiles.push_back(p_interaction_profile);
+ emit_changed();
}
}
@@ -153,6 +156,7 @@ void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p
int idx = interaction_profiles.find(p_interaction_profile);
if (idx != -1) {
interaction_profiles.remove_at(idx);
+ emit_changed();
}
}
@@ -489,30 +493,34 @@ Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const {
return Ref<OpenXRAction>();
}
-void OpenXRActionMap::remove_action(const String p_path) {
+void OpenXRActionMap::remove_action(const String p_path, bool p_remove_interaction_profiles) {
Ref<OpenXRAction> action = get_action(p_path);
if (action.is_valid()) {
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
+
+ if (p_remove_interaction_profiles) {
+ // Remove any bindings for this action
+ interaction_profile->remove_binding_for_action(action);
+ } else {
+ ERR_FAIL_COND(interaction_profile->has_binding_for_action(action));
+ }
+ }
+
OpenXRActionSet *action_set = action->get_action_set();
if (action_set != nullptr) {
// Remove the action from this action set
action_set->remove_action(action);
}
-
- for (int i = 0; i < interaction_profiles.size(); i++) {
- Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
-
- // Remove any bindings for this action
- interaction_profile->remove_binding_for_action(action);
- }
}
}
-PackedStringArray OpenXRActionMap::get_top_level_paths(Ref<OpenXRAction> p_action) {
+PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p_action) {
PackedStringArray arr;
for (int i = 0; i < interaction_profiles.size(); i++) {
Ref<OpenXRInteractionProfile> ip = interaction_profiles[i];
- const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(ip->get_interaction_profile_path());
+ const OpenXRInteractionProfileMetaData::InteractionProfile *profile = OpenXRInteractionProfileMetaData::get_singleton()->get_profile(ip->get_interaction_profile_path());
if (profile != nullptr) {
for (int j = 0; j < ip->get_binding_count(); j++) {
@@ -521,9 +529,9 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(Ref<OpenXRAction> p_actio
PackedStringArray paths = binding->get_paths();
for (int k = 0; k < paths.size(); k++) {
- const OpenXRDefs::IOPath *io_path = profile->get_io_path(paths[k]);
+ const OpenXRInteractionProfileMetaData::IOPath *io_path = profile->get_io_path(paths[k]);
if (io_path != nullptr) {
- String top_path = String(io_path->top_level_path->openxr_path);
+ String top_path = io_path->top_level_path;
if (!arr.has(top_path)) {
arr.push_back(top_path);
@@ -535,7 +543,7 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(Ref<OpenXRAction> p_actio
}
}
- print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr);
+ // print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr);
return arr;
}
diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h
index 8659cd3942..43a4d741f4 100644
--- a/modules/openxr/action_map/openxr_action_map.h
+++ b/modules/openxr/action_map/openxr_action_map.h
@@ -71,8 +71,8 @@ public:
// Helper functions for editor
Ref<OpenXRAction> get_action(const String p_path) const; // Retrieve an action using <action name>/<action> as our parameter
- void remove_action(const String p_path); // Remove action from action set, also removes it from interaction profiles
- PackedStringArray get_top_level_paths(Ref<OpenXRAction> p_action); // Determines the top level paths based on where an action is bound in interaction profiles
+ void remove_action(const String p_path, bool p_remove_interaction_profiles = false); // Remove action from action set, also removes it from interaction profiles
+ PackedStringArray get_top_level_paths(const Ref<OpenXRAction> p_action); // Determines the top level paths based on where an action is bound in interaction profiles
// TODO add validation to display in the interface that checks if we have action sets with the same name or if we have interaction profiles for the same path
diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp
index be45218300..f46ac4a5ce 100644
--- a/modules/openxr/action_map/openxr_action_set.cpp
+++ b/modules/openxr/action_map/openxr_action_set.cpp
@@ -62,6 +62,7 @@ Ref<OpenXRActionSet> OpenXRActionSet::new_action_set(const char *p_name, const c
void OpenXRActionSet::set_localized_name(const String p_localized_name) {
localized_name = p_localized_name;
+ emit_changed();
}
String OpenXRActionSet::get_localized_name() const {
@@ -70,6 +71,7 @@ String OpenXRActionSet::get_localized_name() const {
void OpenXRActionSet::set_priority(const int p_priority) {
priority = p_priority;
+ emit_changed();
}
int OpenXRActionSet::get_priority() const {
@@ -82,11 +84,16 @@ int OpenXRActionSet::get_action_count() const {
void OpenXRActionSet::clear_actions() {
// Actions held within our action set should be released and destroyed but just in case they are still used some where else
+ if (actions.size() == 0) {
+ return;
+ }
+
for (int i = 0; i < actions.size(); i++) {
Ref<OpenXRAction> action = actions[i];
action->action_set = nullptr;
}
actions.clear();
+ emit_changed();
}
void OpenXRActionSet::set_actions(Array p_actions) {
@@ -125,6 +132,7 @@ void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) {
p_action->action_set = this;
actions.push_back(p_action);
+ emit_changed();
}
}
@@ -135,6 +143,8 @@ void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) {
ERR_FAIL_COND_MSG(p_action->action_set != this, "Removing action that belongs to this action set but had incorrect action set pointer."); // this should never happen!
p_action->action_set = nullptr;
+
+ emit_changed();
}
}
diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp
deleted file mode 100644
index 59ce829f1b..0000000000
--- a/modules/openxr/action_map/openxr_defs.cpp
+++ /dev/null
@@ -1,671 +0,0 @@
-/*************************************************************************/
-/* openxr_defs.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.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 "openxr_defs.h"
-
-// Our top level paths to which devices can be bound
-OpenXRDefs::TopLevelPath OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_TOP_LEVEL_PATH_MAX] = {
- // Core OpenXR paths
- { "Left hand controller", "/user/hand/left" },
- { "Right hand controller", "/user/hand/right" },
- { "Head", "/user/head" },
- { "Gamepad", "/user/gamepad" },
- { "Treadmill", "/user/treadmill" },
-
- // Specific to HTC tracker extension
- // { "Handheld object tracker", "/user/vive_tracker_htcx/role/handheld_object" },
- { "Left foot tracker", "/user/vive_tracker_htcx/role/left_foot" },
- { "Right foot tracker", "/user/vive_tracker_htcx/role/right_foot" },
- { "Left shoulder tracker", "/user/vive_tracker_htcx/role/left_shoulder" },
- { "Right shoulder tracker", "/user/vive_tracker_htcx/role/right_shoulder" },
- { "Left elbow tracker", "/user/vive_tracker_htcx/role/left_elbow" },
- { "Right elbow tracker", "/user/vive_tracker_htcx/role/right_elbow" },
- { "Left knee tracker", "/user/vive_tracker_htcx/role/left_knee" },
- { "Right knee tracker", "/user/vive_tracker_htcx/role/right_knee" },
- { "Waist tracker", "/user/vive_tracker_htcx/role/waist" },
- { "Chest tracker", "/user/vive_tracker_htcx/role/chest" },
- { "Camera tracker", "/user/vive_tracker_htcx/role/camera" },
- { "Keyboard tracker", "/user/vive_tracker_htcx/role/keyboard" },
-
-};
-
-// Fallback Khronos simple controller
-OpenXRDefs::IOPath OpenXRDefs::simple_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Original HTC Vive wands
-OpenXRDefs::IOPath OpenXRDefs::vive_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Microsoft motion controller (original WMR controllers)
-OpenXRDefs::IOPath OpenXRDefs::motion_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// HP MR controller (newer G2 controllers)
-OpenXRDefs::IOPath OpenXRDefs::hpmr_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
-OpenXRDefs::IOPath OpenXRDefs::touch_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "X touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Y touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Valve index controller
-OpenXRDefs::IOPath OpenXRDefs::index_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Samsung odyssey controller
-OpenXRDefs::IOPath OpenXRDefs::odyssey_io_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Vive Cosmos controller
-OpenXRDefs::IOPath OpenXRDefs::vive_cosmos_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Vive Focus 3 controller
-OpenXRDefs::IOPath OpenXRDefs::vive_focus3_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch ", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Thumbrest touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbrest/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// Huawei controller
-OpenXRDefs::IOPath OpenXRDefs::huawei_controller_paths[] = {
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-// HTC Vive tracker
-// Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec.
-// I think this can be supported through attachments on the trackers.
-OpenXRDefs::IOPath OpenXRDefs::vive_tracker_controller_paths[] = {
- // { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- // { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
- { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
-
- // { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- // { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- // { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
- { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
-
- // { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
-
- // { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
- { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
-
- // { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
- { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
-
- // { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_HANDHELD_TRACKER], "/user/vive_tracker_htcx/role/handheld_object/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/left_foot/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_FOOT_TRACKER], "/user/vive_tracker_htcx/role/right_foot/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/left_shoulder/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_SHOULDER_TRACKER], "/user/vive_tracker_htcx/role/right_shoulder/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/left_elbow/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_ELBOW_TRACKER], "/user/vive_tracker_htcx/role/right_elbow/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_LEFT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/left_knee/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_RIGHT_KNEE_TRACKER], "/user/vive_tracker_htcx/role/right_knee/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_WAIST_TRACKER], "/user/vive_tracker_htcx/role/waist/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CHEST_TRACKER], "/user/vive_tracker_htcx/role/chest/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_CAMERA_TRACKER], "/user/vive_tracker_htcx/role/camera/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
- { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_HTC_KEYBOARD_TRACKER], "/user/vive_tracker_htcx/role/keyboard/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
-};
-
-OpenXRDefs::InteractionProfile OpenXRDefs::available_interaction_profiles[] = {
- {
- "Simple controller", // display_name
- "/interaction_profiles/khr/simple_controller", // openxr_path
- simple_io_paths, // io_paths
- sizeof(simple_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "HTC Vive wand", // display_name
- "/interaction_profiles/htc/vive_controller", // openxr_path
- vive_io_paths, // io_paths
- sizeof(vive_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "MS Motion controller", // display_name
- "/interaction_profiles/microsoft/motion_controller", // openxr_path
- motion_io_paths, // io_paths
- sizeof(motion_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "HPMR controller", // display_name
- "/interaction_profiles/hp/mixed_reality_controller", // openxr_path
- hpmr_io_paths, // io_paths
- sizeof(hpmr_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "Touch controller", // display_name
- "/interaction_profiles/oculus/touch_controller", // openxr_path
- touch_io_paths, // io_paths
- sizeof(touch_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "Index controller", // display_name
- "/interaction_profiles/valve/index_controller", // openxr_path
- index_io_paths, // io_paths
- sizeof(index_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "Samsung Odyssey controller", // display_name
- "/interaction_profiles/samsung/odyssey_controller", // openxr_path
- odyssey_io_paths, // io_paths
- sizeof(odyssey_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "Vive Cosmos controller", // display_name
- "/interaction_profiles/htc/vive_cosmos_controller", // openxr_path
- vive_cosmos_paths, // io_paths
- sizeof(vive_cosmos_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "Vive Focus 3 controller", // display_name
- "/interaction_profiles/htc/vive_focus3_controller", // openxr_path
- vive_focus3_paths, // io_paths
- sizeof(vive_focus3_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
- {
- "Huawei controller", // display_name
- "/interaction_profiles/huawei/controller", // openxr_path
- huawei_controller_paths, // io_paths
- sizeof(huawei_controller_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
-
- {
- "HTC Vive tracker", // display_name
- "/interaction_profiles/htc/vive_tracker_htcx", // openxr_path
- vive_tracker_controller_paths, // io_paths
- sizeof(vive_tracker_controller_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
- },
-};
-
-int OpenXRDefs::available_interaction_profile_count = sizeof(OpenXRDefs::available_interaction_profiles) / sizeof(OpenXRDefs::InteractionProfile);
-
-const OpenXRDefs::TopLevelPath *OpenXRDefs::get_top_level_path(const String p_top_level_path) {
- for (int i = 0; i < OPENXR_TOP_LEVEL_PATH_MAX; i++) {
- if (available_top_level_paths[i].openxr_path == p_top_level_path) {
- return &OpenXRDefs::available_top_level_paths[i];
- }
- }
-
- return nullptr;
-}
-
-const OpenXRDefs::InteractionProfile *OpenXRDefs::get_profile(const String p_interaction_profile_path) {
- for (int i = 0; i < available_interaction_profile_count; i++) {
- if (available_interaction_profiles[i].openxr_path == p_interaction_profile_path) {
- return &available_interaction_profiles[i];
- }
- }
-
- return nullptr;
-}
-
-const OpenXRDefs::IOPath *OpenXRDefs::InteractionProfile::get_io_path(const String p_io_path) const {
- for (int i = 0; i < available_interaction_profiles[i].io_path_count; i++) {
- if (io_paths[i].openxr_path == p_io_path) {
- return &io_paths[i];
- }
- }
-
- return nullptr;
-}
-
-const OpenXRDefs::IOPath *OpenXRDefs::get_io_path(const String p_interaction_profile_path, const String p_io_path) {
- const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(p_interaction_profile_path);
- if (profile != nullptr) {
- return profile->get_io_path(p_io_path);
- }
-
- return nullptr;
-}
-
-PackedStringArray OpenXRDefs::get_interaction_profile_paths() {
- PackedStringArray arr;
-
- for (int i = 0; i < available_interaction_profile_count; i++) {
- arr.push_back(available_interaction_profiles[i].openxr_path);
- }
-
- return arr;
-}
diff --git a/modules/openxr/action_map/openxr_defs.h b/modules/openxr/action_map/openxr_defs.h
deleted file mode 100644
index 446e6eb9c6..0000000000
--- a/modules/openxr/action_map/openxr_defs.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*************************************************************************/
-/* openxr_defs.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.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. */
-/*************************************************************************/
-
-#ifndef OPENXR_DEFS_H
-#define OPENXR_DEFS_H
-
-#include "openxr_action.h"
-
-///////////////////////////////////////////////////////////////////////////
-// Stores available interaction profiles
-//
-// OpenXR defines and hardcodes all the supported input devices and their
-// paths as part of the OpenXR spec. When support for new devices is
-// introduced this often starts life as extensions that need to be enabled
-// until they are adopted into the core. As there is no interface to
-// enumerate the possibly paths, and that any OpenXR runtime would likely
-// limit such enumeration to those input devices supported by that runtime
-// there is no other option than to hardcode this.
-//
-// Note on action type that automatic conversions between boolean and float
-// are supported but otherwise action types should match between action and
-// input/output paths.
-
-class OpenXRDefs {
-public:
- enum TOP_LEVEL_PATH {
- // Core OpenXR toplevel paths
- OPENXR_LEFT_HAND,
- OPENXR_RIGHT_HAND,
- OPENXR_HEAD,
- OPENXR_GAMEPAD,
- OPENXR_TREADMILL,
-
- // HTC tracker extension toplevel paths
- // OPENXR_HTC_HANDHELD_TRACKER,
- OPENXR_HTC_LEFT_FOOT_TRACKER,
- OPENXR_HTC_RIGHT_FOOT_TRACKER,
- OPENXR_HTC_LEFT_SHOULDER_TRACKER,
- OPENXR_HTC_RIGHT_SHOULDER_TRACKER,
- OPENXR_HTC_LEFT_ELBOW_TRACKER,
- OPENXR_HTC_RIGHT_ELBOW_TRACKER,
- OPENXR_HTC_LEFT_KNEE_TRACKER,
- OPENXR_HTC_RIGHT_KNEE_TRACKER,
- OPENXR_HTC_WAIST_TRACKER,
- OPENXR_HTC_CHEST_TRACKER,
- OPENXR_HTC_CAMERA_TRACKER,
- OPENXR_HTC_KEYBOARD_TRACKER,
-
- OPENXR_TOP_LEVEL_PATH_MAX
- };
-
- struct TopLevelPath {
- const char *display_name; // User friendly display name (i.e. Left controller)
- const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left)
- };
-
- struct IOPath {
- const char *display_name; // User friendly display name (i.e. Grip pose (left controller))
- const TopLevelPath *top_level_path; // Top level path identifying the usage of the device in relation to this input/output
- const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left/input/grip/pose)
- const OpenXRAction::ActionType action_type; // Type of input/output
- };
-
- struct InteractionProfile {
- const char *display_name; // User friendly display name (i.e. Simple controller)
- const char *openxr_path; // Path in OpenXR (i.e. /interaction_profiles/khr/simple_controller)
- const IOPath *io_paths; // Inputs and outputs for this device
- const int io_path_count; // Number of inputs and outputs for this device
-
- const IOPath *get_io_path(const String p_io_path) const;
- };
-
-private:
- static TopLevelPath available_top_level_paths[OPENXR_TOP_LEVEL_PATH_MAX];
- static IOPath simple_io_paths[];
- static IOPath vive_io_paths[];
- static IOPath motion_io_paths[];
- static IOPath hpmr_io_paths[];
- static IOPath touch_io_paths[];
- static IOPath index_io_paths[];
- static IOPath odyssey_io_paths[];
- static IOPath vive_cosmos_paths[];
- static IOPath vive_focus3_paths[];
- static IOPath huawei_controller_paths[];
- static IOPath vive_tracker_controller_paths[];
- static InteractionProfile available_interaction_profiles[];
- static int available_interaction_profile_count;
-
-public:
- static const TopLevelPath *get_top_level_path(const String p_top_level_path);
- static const InteractionProfile *get_profile(const String p_interaction_profile_path);
- static const IOPath *get_io_path(const String p_interaction_profile_path, const String p_io_path);
-
- static PackedStringArray get_interaction_profile_paths();
-};
-
-#endif // OPENXR_DEFS_H
diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp
index abb714c3bb..8bb657a2db 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile.cpp
@@ -58,6 +58,7 @@ Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_acti
void OpenXRIPBinding::set_action(const Ref<OpenXRAction> p_action) {
action = p_action;
+ emit_changed();
}
Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
@@ -70,6 +71,7 @@ int OpenXRIPBinding::get_path_count() const {
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
paths = p_paths;
+ emit_changed();
}
PackedStringArray OpenXRIPBinding::get_paths() const {
@@ -78,6 +80,7 @@ PackedStringArray OpenXRIPBinding::get_paths() const {
void OpenXRIPBinding::parse_paths(const String p_paths) {
paths = p_paths.split(",", false);
+ emit_changed();
}
bool OpenXRIPBinding::has_path(const String p_path) const {
@@ -87,12 +90,14 @@ bool OpenXRIPBinding::has_path(const String p_path) const {
void OpenXRIPBinding::add_path(const String p_path) {
if (!paths.has(p_path)) {
paths.push_back(p_path);
+ emit_changed();
}
}
void OpenXRIPBinding::remove_path(const String p_path) {
if (paths.has(p_path)) {
paths.erase(p_path);
+ emit_changed();
}
}
@@ -122,6 +127,7 @@ Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char *
void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) {
interaction_profile_path = p_input_profile_path;
+ emit_changed();
}
String OpenXRInteractionProfile::get_interaction_profile_path() const {
@@ -139,9 +145,10 @@ Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
}
void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
- bindings = p_bindings;
-
// TODO add check here that our bindings don't contain duplicate actions
+
+ bindings = p_bindings;
+ emit_changed();
}
Array OpenXRInteractionProfile::get_bindings() const {
@@ -166,6 +173,7 @@ void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile");
bindings.push_back(p_binding);
+ emit_changed();
}
}
@@ -173,6 +181,7 @@ void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) {
int idx = bindings.find(p_binding);
if (idx != -1) {
bindings.remove_at(idx);
+ emit_changed();
}
}
@@ -192,6 +201,17 @@ void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction>
}
}
+bool OpenXRInteractionProfile::has_binding_for_action(const Ref<OpenXRAction> p_action) {
+ for (int i = bindings.size() - 1; i >= 0; i--) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->get_action() == p_action) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
OpenXRInteractionProfile::~OpenXRInteractionProfile() {
bindings.clear();
}
diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h
index c77fd490bb..c7db77870e 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.h
+++ b/modules/openxr/action_map/openxr_interaction_profile.h
@@ -34,7 +34,7 @@
#include "core/io/resource.h"
#include "openxr_action.h"
-#include "openxr_defs.h"
+#include "openxr_interaction_profile_meta_data.h"
class OpenXRIPBinding : public Resource {
GDCLASS(OpenXRIPBinding, Resource);
@@ -94,6 +94,7 @@ public:
void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Create a new binding for this profile
void remove_binding_for_action(const Ref<OpenXRAction> p_action); // Remove all bindings for this action
+ bool has_binding_for_action(const Ref<OpenXRAction> p_action); // Returns true if we have a binding for this action
~OpenXRInteractionProfile();
};
diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
new file mode 100644
index 0000000000..db4062b196
--- /dev/null
+++ b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
@@ -0,0 +1,713 @@
+/*************************************************************************/
+/* openxr_interaction_profile_meta_data.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.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 "openxr_interaction_profile_meta_data.h"
+
+#include <openxr/openxr.h>
+
+OpenXRInteractionProfileMetaData *OpenXRInteractionProfileMetaData::singleton = nullptr;
+
+OpenXRInteractionProfileMetaData::OpenXRInteractionProfileMetaData() {
+ singleton = this;
+
+ _register_core_metadata();
+}
+
+OpenXRInteractionProfileMetaData::~OpenXRInteractionProfileMetaData() {
+ singleton = nullptr;
+}
+
+void OpenXRInteractionProfileMetaData::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("register_top_level_path", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetaData::register_top_level_path);
+ ClassDB::bind_method(D_METHOD("register_interaction_profile", "display_name", "openxr_path", "openxr_extension_name"), &OpenXRInteractionProfileMetaData::register_interaction_profile);
+ ClassDB::bind_method(D_METHOD("register_io_path", "interaction_profile", "display_name", "toplevel_path", "openxr_path", "openxr_extension_name", "action_type"), &OpenXRInteractionProfileMetaData::register_io_path);
+}
+
+void OpenXRInteractionProfileMetaData::register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) {
+ ERR_FAIL_COND_MSG(has_top_level_path(p_openxr_path), p_openxr_path + " had already been registered");
+
+ TopLevelPath new_toplevel_path = {
+ p_display_name,
+ p_openxr_path,
+ p_openxr_extension_name
+ };
+
+ top_level_paths.push_back(new_toplevel_path);
+}
+
+void OpenXRInteractionProfileMetaData::register_interaction_profile(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name) {
+ ERR_FAIL_COND_MSG(has_interaction_profile(p_openxr_path), p_openxr_path + " has already been registered");
+
+ InteractionProfile new_profile;
+ new_profile.display_name = p_display_name;
+ new_profile.openxr_path = p_openxr_path;
+ new_profile.openxr_extension_name = p_openxr_extension_name;
+
+ interaction_profiles.push_back(new_profile);
+}
+
+void OpenXRInteractionProfileMetaData::register_io_path(const String &p_interaction_profile, const String &p_display_name, const String &p_toplevel_path, const String &p_openxr_path, const String &p_openxr_extension_name, OpenXRAction::ActionType p_action_type) {
+ ERR_FAIL_COND_MSG(!has_interaction_profile(p_interaction_profile), "Unknown interaction profile " + p_interaction_profile);
+ ERR_FAIL_COND_MSG(!has_top_level_path(p_toplevel_path), "Unknown top level path " + p_toplevel_path);
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ if (interaction_profiles[i].openxr_path == p_interaction_profile) {
+ ERR_FAIL_COND_MSG(interaction_profiles[i].has_io_path(p_openxr_path), p_interaction_profile + " already has io path " + p_openxr_path + " registered!");
+
+ IOPath new_io_path = {
+ p_display_name,
+ p_toplevel_path,
+ p_openxr_path,
+ p_openxr_extension_name,
+ p_action_type
+ };
+
+ interaction_profiles.ptrw()[i].io_paths.push_back(new_io_path);
+ }
+ }
+}
+
+bool OpenXRInteractionProfileMetaData::has_top_level_path(const String p_openxr_path) const {
+ for (int i = 0; i < top_level_paths.size(); i++) {
+ if (top_level_paths[i].openxr_path == p_openxr_path) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+String OpenXRInteractionProfileMetaData::get_top_level_name(const String p_openxr_path) const {
+ for (int i = 0; i < top_level_paths.size(); i++) {
+ if (top_level_paths[i].openxr_path == p_openxr_path) {
+ return top_level_paths[i].display_name;
+ }
+ }
+
+ return String();
+}
+
+String OpenXRInteractionProfileMetaData::get_top_level_extension(const String p_openxr_path) const {
+ for (int i = 0; i < top_level_paths.size(); i++) {
+ if (top_level_paths[i].openxr_path == p_openxr_path) {
+ return top_level_paths[i].openxr_extension_name;
+ }
+ }
+
+ return XR_PATH_UNSUPPORTED_NAME;
+}
+
+bool OpenXRInteractionProfileMetaData::has_interaction_profile(const String p_openxr_path) const {
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ if (interaction_profiles[i].openxr_path == p_openxr_path) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+String OpenXRInteractionProfileMetaData::get_interaction_profile_extension(const String p_openxr_path) const {
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ if (interaction_profiles[i].openxr_path == p_openxr_path) {
+ return interaction_profiles[i].openxr_extension_name;
+ }
+ }
+
+ return XR_PATH_UNSUPPORTED_NAME;
+}
+
+const OpenXRInteractionProfileMetaData::InteractionProfile *OpenXRInteractionProfileMetaData::get_profile(const String p_openxr_path) const {
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ if (interaction_profiles[i].openxr_path == p_openxr_path) {
+ return &interaction_profiles[i];
+ }
+ }
+
+ return nullptr;
+}
+
+bool OpenXRInteractionProfileMetaData::InteractionProfile::has_io_path(const String p_io_path) const {
+ for (int i = 0; i < io_paths.size(); i++) {
+ if (io_paths[i].openxr_path == p_io_path) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const OpenXRInteractionProfileMetaData::IOPath *OpenXRInteractionProfileMetaData::InteractionProfile::get_io_path(const String p_io_path) const {
+ for (int i = 0; i < io_paths.size(); i++) {
+ if (io_paths[i].openxr_path == p_io_path) {
+ return &io_paths[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRInteractionProfileMetaData::IOPath *OpenXRInteractionProfileMetaData::get_io_path(const String p_interaction_profile, const String p_io_path) const {
+ const OpenXRInteractionProfileMetaData::InteractionProfile *profile = get_profile(p_interaction_profile);
+ if (profile != nullptr) {
+ return profile->get_io_path(p_io_path);
+ }
+
+ return nullptr;
+}
+
+PackedStringArray OpenXRInteractionProfileMetaData::get_interaction_profile_paths() const {
+ PackedStringArray arr;
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ arr.push_back(interaction_profiles[i].openxr_path);
+ }
+
+ return arr;
+}
+
+void OpenXRInteractionProfileMetaData::_register_core_metadata() {
+ // Note, currently we add definitions that belong in extensions.
+ // Extensions are registered when our OpenXRAPI is instantiated
+ // however this does not happen in the editor.
+ // We are changing this in another PR, once that is accepted we
+ // can make the changes to move code into extensions where needed.
+
+ // Note that we'll make an exception for XR_EXT_palm_pose, which is used everywhere
+
+ // Our core toplevel paths
+ register_top_level_path("Left hand controller", "/user/hand/left", "");
+ register_top_level_path("Right hand controller", "/user/hand/right", "");
+ register_top_level_path("Head", "/user/head", "");
+ register_top_level_path("Gamepad", "/user/gamepad", "");
+ register_top_level_path("Treadmill", "/user/treadmill", "");
+
+ // TODO move this into OpenXRHTCViveTrackerExtension once this is supported.
+ // register_top_level_path("Handheld object tracker", "/user/vive_tracker_htcx/role/handheld_object", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Left foot tracker", "/user/vive_tracker_htcx/role/left_foot", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Right foot tracker", "/user/vive_tracker_htcx/role/right_foot", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Left shoulder tracker", "/user/vive_tracker_htcx/role/left_shoulder", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Right shoulder tracker", "/user/vive_tracker_htcx/role/right_shoulder", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Left elbow tracker", "/user/vive_tracker_htcx/role/left_elbow", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Right elbow tracker", "/user/vive_tracker_htcx/role/right_elbow", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Left knee tracker", "/user/vive_tracker_htcx/role/left_knee", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Right knee tracker", "/user/vive_tracker_htcx/role/right_knee", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Waist tracker", "/user/vive_tracker_htcx/role/waist", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Chest tracker", "/user/vive_tracker_htcx/role/chest", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Camera tracker", "/user/vive_tracker_htcx/role/camera", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_top_level_path("Keyboard tracker", "/user/vive_tracker_htcx/role/keyboard", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+
+ // Fallback Khronos simple controller
+ register_interaction_profile("Simple controller", "/interaction_profiles/khr/simple_controller", "");
+ register_io_path("/interaction_profiles/khr/simple_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/khr/simple_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Select click", "/user/hand/left", "/user/hand/left/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Select click", "/user/hand/right", "/user/hand/right/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/khr/simple_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/khr/simple_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Original HTC Vive wands
+ register_interaction_profile("HTC Vive wand", "/interaction_profiles/htc/vive_controller", "");
+ register_io_path("/interaction_profiles/htc/vive_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/htc/vive_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Microsoft motion controller (original WMR controllers)
+ register_interaction_profile("MS Motion controller", "/interaction_profiles/microsoft/motion_controller", "");
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/microsoft/motion_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
+ register_interaction_profile("Touch controller", "/interaction_profiles/oculus/touch_controller", "");
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/oculus/touch_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Valve Index controller
+ register_interaction_profile("Index controller", "/interaction_profiles/valve/index_controller", "");
+ register_io_path("/interaction_profiles/valve/index_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/valve/index_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/valve/index_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/valve/index_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/valve/index_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/valve/index_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "A click", "/user/hand/left", "/user/hand/left/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "A touch", "/user/hand/left", "/user/hand/left/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "B click", "/user/hand/left", "/user/hand/left/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "B touch", "/user/hand/left", "/user/hand/left/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trackpad force", "/user/hand/left", "/user/hand/left/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trackpad force", "/user/hand/right", "/user/hand/right/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // HP MR controller (newer G2 controllers)
+ // TODO move this into an extension once this is supported.
+ register_interaction_profile("HPMR controller", "/interaction_profiles/hp/mixed_reality_controller", XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Samsung Odyssey controller
+ // TODO move this into an extension once this is supported.
+ register_interaction_profile("Samsung Odyssey controller", "/interaction_profiles/samsung/odyssey_controller", XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // HTC Vive Cosmos controller
+ // TODO move this into an extension once this is supported.
+ register_interaction_profile("Vive Cosmos controller", "/interaction_profiles/htc/vive_cosmos_controller", XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/left", "/user/hand/left/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/right", "/user/hand/right/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // HTC Vive Focus 3 controller
+ // TODO move this into an extension once this is supported.
+ register_interaction_profile("Vive Focus 3 controller", "/interaction_profiles/htc/vive_focus3_controller", XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch ", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/left", "/user/hand/left/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/right", "/user/hand/right/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // Huawei controller
+ // TODO move this into an extension once this is supported.
+ register_interaction_profile("Huawei controller", "/interaction_profiles/huawei/controller", XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/left", "/user/hand/left/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/right", "/user/hand/right/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/left", "/user/hand/left/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/right", "/user/hand/right/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/left", "/user/hand/left/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/right", "/user/hand/right/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/left", "/user/hand/left/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/right", "/user/hand/right/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+
+ // HTC Vive tracker
+ // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec.
+ // I think this can be supported through attachments on the trackers.
+ // TODO move this into an extension once this is supported.
+ register_interaction_profile("HTC Vive tracker", "/interaction_profiles/htc/vive_tracker_htcx", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+
+ // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+}
diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.h b/modules/openxr/action_map/openxr_interaction_profile_meta_data.h
new file mode 100644
index 0000000000..0ae6454be7
--- /dev/null
+++ b/modules/openxr/action_map/openxr_interaction_profile_meta_data.h
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* openxr_interaction_profile_meta_data.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.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. */
+/*************************************************************************/
+
+#ifndef OPENXR_INTERACTION_PROFILE_META_DATA_H
+#define OPENXR_INTERACTION_PROFILE_META_DATA_H
+
+#include "openxr_action.h"
+
+///////////////////////////////////////////////////////////////////////////
+// Stores available interaction profile meta data
+//
+// OpenXR defines and hardcodes all the supported input devices and their
+// paths as part of the OpenXR spec. When support for new devices is
+// introduced this often starts life as an extension that needs to be enabled
+// until it's adopted into the core. As there is no interface to
+// enumerate the possibly paths, and that any OpenXR runtime would likely
+// limit such enumeration to those input devices supported by that runtime
+// there is no other option than to hardcode this.
+//
+// Note that we need to include paths of our extensions in our action map
+// regardless of whether the developers machine supports the extension or
+// not. Unsupported paths are filtered out when the action map is submitted
+// to the OpenXR runtime.
+//
+// Note on action type that automatic conversions between boolean and float
+// are supported but otherwise action types should match between action and
+// input/output paths.
+
+#include "core/object/object.h"
+
+#define XR_PATH_UNSUPPORTED_NAME "unsupported"
+
+class OpenXRInteractionProfileMetaData : public Object {
+public:
+ struct TopLevelPath {
+ String display_name; // User friendly display name (i.e. Left controller)
+ String openxr_path; // Path in OpenXR (i.e. /user/hand/left)
+ String openxr_extension_name; // If set, only available if extension is enabled (i.e. XR_HTCX_vive_tracker_interaction)
+ };
+
+ struct IOPath {
+ String display_name; // User friendly display name (i.e. Grip pose (left controller))
+ String top_level_path; // Top level path identifying the usage of the device in relation to this input/output
+ String openxr_path; // Path in OpenXR (i.e. /user/hand/left/input/grip/pose)
+ String openxr_extension_name; // If set, only available if extension is enabled (i.e. XR_EXT_palm_pose)
+ OpenXRAction::ActionType action_type; // Type of input/output
+ };
+
+ struct InteractionProfile {
+ String display_name; // User friendly display name (i.e. Simple controller)
+ String openxr_path; // Path in OpenXR (i.e. /interaction_profiles/khr/simple_controller)
+ String openxr_extension_name; // If set, only available if extension is enabled (i.e. XR_HTCX_vive_tracker_interaction)
+ Vector<IOPath> io_paths; // Inputs and outputs for this device
+
+ bool has_io_path(const String p_io_path) const;
+ const IOPath *get_io_path(const String p_io_path) const;
+ };
+
+private:
+ static OpenXRInteractionProfileMetaData *singleton;
+
+ Vector<TopLevelPath> top_level_paths;
+ Vector<InteractionProfile> interaction_profiles;
+
+ void _register_core_metadata();
+
+protected:
+ static void _bind_methods();
+
+public:
+ static OpenXRInteractionProfileMetaData *get_singleton() { return singleton; }
+
+ OpenXRInteractionProfileMetaData();
+ ~OpenXRInteractionProfileMetaData();
+
+ void register_top_level_path(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name);
+ bool has_top_level_path(const String p_openxr_path) const;
+ String get_top_level_name(const String p_openxr_path) const;
+ String get_top_level_extension(const String p_openxr_path) const;
+
+ void register_interaction_profile(const String &p_display_name, const String &p_openxr_path, const String &p_openxr_extension_name);
+ bool has_interaction_profile(const String p_openxr_path) const;
+ String get_interaction_profile_extension(const String p_openxr_path) const;
+ const InteractionProfile *get_profile(const String p_openxr_path) const;
+ PackedStringArray get_interaction_profile_paths() const;
+
+ void register_io_path(const String &p_interaction_profile, const String &p_display_name, const String &p_toplevel_path, const String &p_openxr_path, const String &p_openxr_extension_name, OpenXRAction::ActionType p_action_type);
+ const IOPath *get_io_path(const String p_interaction_profile, const String p_io_path) const;
+};
+
+#endif // OPENXR_INTERACTION_PROFILE_META_DATA_H
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
index 52216fa483..a6c99741d7 100644
--- a/modules/openxr/editor/openxr_action_editor.cpp
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -29,8 +29,13 @@
/*************************************************************************/
#include "openxr_action_editor.h"
+#include "editor/editor_node.h"
void OpenXRActionEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionEditor::_do_set_name);
+ ClassDB::bind_method(D_METHOD("_do_set_localized_name", "name"), &OpenXRActionEditor::_do_set_localized_name);
+ ClassDB::bind_method(D_METHOD("_do_set_action_type", "type"), &OpenXRActionEditor::_do_set_action_type);
+
ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor")));
}
@@ -48,24 +53,71 @@ void OpenXRActionEditor::_notification(int p_what) {
}
void OpenXRActionEditor::_on_action_name_changed(const String p_new_text) {
- // TODO validate if entry is allowed
-
- // If our localized name matches our action name, set this too
- if (action->get_name() == action->get_localized_name()) {
- action->set_localized_name(p_new_text);
- action_localized_name->set_text(p_new_text);
+ if (action->get_name() != p_new_text) {
+ undo_redo->create_action(TTR("Rename Action"));
+ undo_redo->add_do_method(this, "_do_set_name", p_new_text);
+ undo_redo->add_undo_method(this, "_do_set_name", action->get_name());
+ undo_redo->commit_action(false);
+
+ // If our localized name matches our action name, set this too
+ if (action->get_name() == action->get_localized_name()) {
+ undo_redo->create_action(TTR("Rename Actions Localized name"));
+ undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
+ undo_redo->add_undo_method(this, "_do_set_localized_name", action->get_localized_name());
+ undo_redo->commit_action(false);
+
+ action->set_localized_name(p_new_text);
+ action_localized_name->set_text(p_new_text);
+ }
+ action->set_name(p_new_text);
+ action->set_edited(true);
}
+}
+
+void OpenXRActionEditor::_do_set_name(const String p_new_text) {
action->set_name(p_new_text);
+ action->set_edited(true);
+ action_name->set_text(p_new_text);
}
void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_text) {
+ if (action->get_localized_name() != p_new_text) {
+ undo_redo->create_action(TTR("Rename Actions Localized name"));
+ undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
+ undo_redo->add_undo_method(this, "_do_set_localized_name", action->get_localized_name());
+ undo_redo->commit_action(false);
+
+ action->set_localized_name(p_new_text);
+ action->set_edited(true);
+ }
+}
+
+void OpenXRActionEditor::_do_set_localized_name(const String p_new_text) {
action->set_localized_name(p_new_text);
+ action->set_edited(true);
+ action_localized_name->set_text(p_new_text);
}
void OpenXRActionEditor::_on_item_selected(int p_idx) {
ERR_FAIL_INDEX(p_idx, OpenXRAction::OPENXR_ACTION_MAX);
- action->set_action_type(OpenXRAction::ActionType(p_idx));
+ OpenXRAction::ActionType action_type = OpenXRAction::ActionType(p_idx);
+
+ if (action->get_action_type() != action_type) {
+ undo_redo->create_action(TTR("Change Action Type"));
+ undo_redo->add_do_method(this, "_do_set_action_type", action_type);
+ undo_redo->add_undo_method(this, "_do_set_action_type", action->get_action_type());
+ undo_redo->commit_action(false);
+
+ action->set_action_type(action_type);
+ action->set_edited(true);
+ }
+}
+
+void OpenXRActionEditor::_do_set_action_type(OpenXRAction::ActionType p_action_type) {
+ action->set_action_type(p_action_type);
+ action->set_edited(true);
+ action_type_button->select(int(action->get_action_type()));
}
void OpenXRActionEditor::_on_remove_action() {
@@ -73,6 +125,7 @@ void OpenXRActionEditor::_on_remove_action() {
}
OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
+ undo_redo = EditorNode::get_undo_redo();
action = p_action;
set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -90,16 +143,16 @@ OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
action_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_localized_name_changed));
add_child(action_localized_name);
- action_type = memnew(OptionButton);
- action_type->add_item("Bool", OpenXRAction::OPENXR_ACTION_BOOL);
- action_type->add_item("Float", OpenXRAction::OPENXR_ACTION_FLOAT);
- action_type->add_item("Vector2", OpenXRAction::OPENXR_ACTION_VECTOR2);
- action_type->add_item("Pose", OpenXRAction::OPENXR_ACTION_POSE);
- action_type->add_item("Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC);
- action_type->select(int(action->get_action_type()));
- action_type->set_custom_minimum_size(Size2(100.0, 0.0));
- action_type->connect("item_selected", callable_mp(this, &OpenXRActionEditor::_on_item_selected));
- add_child(action_type);
+ action_type_button = memnew(OptionButton);
+ action_type_button->add_item("Bool", OpenXRAction::OPENXR_ACTION_BOOL);
+ action_type_button->add_item("Float", OpenXRAction::OPENXR_ACTION_FLOAT);
+ action_type_button->add_item("Vector2", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ action_type_button->add_item("Pose", OpenXRAction::OPENXR_ACTION_POSE);
+ action_type_button->add_item("Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ action_type_button->select(int(action->get_action_type()));
+ action_type_button->set_custom_minimum_size(Size2(100.0, 0.0));
+ action_type_button->connect("item_selected", callable_mp(this, &OpenXRActionEditor::_on_item_selected));
+ add_child(action_type_button);
// maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings?
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
index 6cf098cf08..66b7eebaeb 100644
--- a/modules/openxr/editor/openxr_action_editor.h
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -32,6 +32,7 @@
#define OPENXR_ACTION_EDITOR_H
#include "../action_map/openxr_action.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/line_edit.h"
@@ -42,11 +43,12 @@ class OpenXRActionEditor : public HBoxContainer {
GDCLASS(OpenXRActionEditor, HBoxContainer);
private:
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<OpenXRAction> action;
LineEdit *action_name = nullptr;
LineEdit *action_localized_name = nullptr;
- OptionButton *action_type = nullptr;
+ OptionButton *action_type_button = nullptr;
Button *rem_action = nullptr;
void _theme_changed();
@@ -59,6 +61,11 @@ protected:
static void _bind_methods();
void _notification(int p_what);
+ // used for undo/redo
+ void _do_set_name(const String p_new_text);
+ void _do_set_localized_name(const String p_new_text);
+ void _do_set_action_type(OpenXRAction::ActionType p_action_type);
+
public:
Ref<OpenXRAction> get_action() { return action; };
OpenXRActionEditor(Ref<OpenXRAction> p_action);
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index b5223e5903..a2c33a91c4 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -40,14 +40,16 @@
void OpenXRActionMapEditor::_bind_methods() {
ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor);
- ClassDB::bind_method("_update_action_sets", &OpenXRActionMapEditor::_update_action_sets);
-
ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor);
- ClassDB::bind_method("_update_interaction_profiles", &OpenXRActionMapEditor::_update_interaction_profiles);
ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set);
ClassDB::bind_method(D_METHOD("_set_focus_on_action_set", "action_set"), &OpenXRActionMapEditor::_set_focus_on_action_set);
ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set);
+
+ ClassDB::bind_method(D_METHOD("_do_add_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_add_action_set_editor);
+ ClassDB::bind_method(D_METHOD("_do_remove_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_remove_action_set_editor);
+ ClassDB::bind_method(D_METHOD("_do_add_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_add_interaction_profile_editor);
+ ClassDB::bind_method(D_METHOD("_do_remove_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_remove_interaction_profile_editor);
}
void OpenXRActionMapEditor::_notification(int p_what) {
@@ -63,8 +65,8 @@ void OpenXRActionMapEditor::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- _update_action_sets();
- _update_interaction_profiles();
+ _create_action_sets();
+ _create_interaction_profiles();
} break;
}
}
@@ -75,18 +77,13 @@ OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(Ref<OpenXRA
OpenXRActionSetEditor *action_set_editor = memnew(OpenXRActionSetEditor(action_map, p_action_set));
action_set_editor->connect("remove", callable_mp(this, &OpenXRActionMapEditor::_on_remove_action_set));
action_set_editor->connect("action_removed", callable_mp(this, &OpenXRActionMapEditor::_on_action_removed));
+
actionsets_vb->add_child(action_set_editor);
return action_set_editor;
}
-void OpenXRActionMapEditor::_update_action_sets() {
- // out with the old...
- while (actionsets_vb->get_child_count() > 0) {
- memdelete(actionsets_vb->get_child(0));
- }
-
- // in with the new...
+void OpenXRActionMapEditor::_create_action_sets() {
if (action_map.is_valid()) {
Array action_sets = action_map->get_action_sets();
for (int i = 0; i < action_sets.size(); i++) {
@@ -116,22 +113,10 @@ OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_prof
new_profile_editor->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
- interaction_profiles.push_back(new_profile_editor);
-
return new_profile_editor;
}
-void OpenXRActionMapEditor::_update_interaction_profiles() {
- // out with the old...
- while (interaction_profiles.size() > 0) {
- Node *interaction_profile = interaction_profiles[0];
- interaction_profiles.remove_at(0);
-
- tabs->remove_child(interaction_profile);
- interaction_profile->queue_free();
- }
-
- // in with the new...
+void OpenXRActionMapEditor::_create_interaction_profiles() {
if (action_map.is_valid()) {
Array new_interaction_profiles = action_map->get_interaction_profiles();
for (int i = 0; i < new_interaction_profiles.size(); i++) {
@@ -150,9 +135,17 @@ OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(String p_name) {
new_action_set->set_name(p_name);
new_action_set->set_localized_name(p_name);
action_map->add_action_set(new_action_set);
+ action_map->set_edited(true);
// update our editor right away
- return _add_action_set_editor(new_action_set);
+ OpenXRActionSetEditor *action_set_editor = _add_action_set_editor(new_action_set);
+
+ undo_redo->create_action(TTR("Add action set"));
+ undo_redo->add_do_method(this, "_do_add_action_set_editor", action_set_editor);
+ undo_redo->add_undo_method(this, "_do_remove_action_set_editor", action_set_editor);
+ undo_redo->commit_action(false);
+
+ return action_set_editor;
}
void OpenXRActionMapEditor::_remove_action_set(String p_name) {
@@ -160,13 +153,12 @@ void OpenXRActionMapEditor::_remove_action_set(String p_name) {
Ref<OpenXRActionSet> action_set = action_map->find_action_set(p_name);
ERR_FAIL_COND(action_set.is_null());
- if (action_set->get_action_count() > 0) {
- // we should remove these and add to our redo/undo step before calling _remove_action_set
- WARN_PRINT("Action set still has associated actions before being removed!");
+ for (int i = 0; i < actionsets_vb->get_child_count(); i++) {
+ OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(actionsets_vb->get_child(i));
+ if (action_set_editor && action_set_editor->get_action_set() == action_set) {
+ _on_remove_action_set(action_set_editor);
+ }
}
-
- // now we remove it
- action_map->remove_action_set(action_set);
}
void OpenXRActionMapEditor::_on_add_action_set() {
@@ -203,14 +195,23 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
Ref<OpenXRActionSet> action_set = action_set_editor->get_action_set();
ERR_FAIL_COND(action_set.is_null());
- action_map->remove_action_set(action_set);
- actionsets_vb->remove_child(action_set_editor);
- action_set_editor->queue_free();
+ action_set_editor->remove_all_actions();
+
+ undo_redo->create_action(TTR("Remove action set"));
+ undo_redo->add_do_method(this, "_do_remove_action_set_editor", action_set_editor);
+ undo_redo->add_undo_method(this, "_do_add_action_set_editor", action_set_editor);
+ undo_redo->commit_action(true);
+
+ action_map->set_edited(true);
}
void OpenXRActionMapEditor::_on_action_removed() {
- // make sure our interaction profiles are updated
- _update_interaction_profiles();
+ for (int i = 0; i < tabs->get_tab_count(); i++) {
+ // First tab won't be an interaction profile editor, but being thorough..
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(i));
+ if (interaction_profile_editor) {
+ }
+ }
}
void OpenXRActionMapEditor::_on_add_interaction_profile() {
@@ -232,20 +233,35 @@ void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path
new_profile.instantiate();
new_profile->set_interaction_profile_path(p_path);
action_map->add_interaction_profile(new_profile);
+ action_map->set_edited(true);
- _add_interaction_profile_editor(new_profile);
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = _add_interaction_profile_editor(new_profile);
+
+ undo_redo->create_action(TTR("Add interaction profile"));
+ undo_redo->add_do_method(this, "_do_add_interaction_profile_editor", interaction_profile_editor);
+ undo_redo->add_undo_method(this, "_do_remove_interaction_profile_editor", interaction_profile_editor);
+ undo_redo->commit_action(false);
tabs->set_current_tab(tabs->get_tab_count() - 1);
}
void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) {
- action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
- if (action_map.is_null()) {
- if (p_create_new_if_missing) {
+ Error err = OK;
+ action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
+ if (err != OK) {
+ if ((err == ERR_FILE_NOT_FOUND || err == ERR_CANT_OPEN) && p_create_new_if_missing) {
action_map.instantiate();
action_map->create_default_action_sets();
+
+ // Save it immediately
+ err = ResourceSaver::save(action_map, p_path);
+ if (err != OK) {
+ // show warning but continue
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err]));
+ }
+
} else {
- EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an OpenXR action map."));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Error loading %s: %s."), edited_path, error_names[err]));
edited_path = "";
header_label->set_text("");
@@ -254,55 +270,123 @@ void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_
}
edited_path = p_path;
- header_label->set_text(TTR("OpenXR Action map:") + " " + p_path.get_file());
+ header_label->set_text(TTR("OpenXR Action map:") + " " + edited_path.get_file());
}
void OpenXRActionMapEditor::_on_save_action_map() {
Error err = ResourceSaver::save(action_map, edited_path);
if (err != OK) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), edited_path));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err]));
return;
}
- _update_action_sets();
- _update_interaction_profiles();
+ // TODO should clear undo/redo history
+
+ // out with the old
+ _clear_action_map();
+
+ _create_action_sets();
+ _create_interaction_profiles();
}
void OpenXRActionMapEditor::_on_reset_to_default_layout() {
+ // TODO should clear undo/redo history
+
+ // out with the old
+ _clear_action_map();
+
// create a new one
action_map.unref();
action_map.instantiate();
action_map->create_default_action_sets();
+ action_map->set_edited(true);
- _update_action_sets();
- _update_interaction_profiles();
+ _create_action_sets();
+ _create_interaction_profiles();
}
void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) {
}
void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
- OpenXRInteractionProfileEditorBase *profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(p_tab));
- ERR_FAIL_NULL(profile_editor);
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(p_tab));
+ ERR_FAIL_NULL(interaction_profile_editor);
+
+ undo_redo->create_action(TTR("Remove interaction profile"));
+ undo_redo->add_do_method(this, "_do_remove_interaction_profile_editor", interaction_profile_editor);
+ undo_redo->add_undo_method(this, "_do_add_interaction_profile_editor", interaction_profile_editor);
+ undo_redo->commit_action(true);
+
+ action_map->set_edited(true);
+}
+
+void OpenXRActionMapEditor::_do_add_action_set_editor(OpenXRActionSetEditor *p_action_set_editor) {
+ Ref<OpenXRActionSet> action_set = p_action_set_editor->get_action_set();
+ ERR_FAIL_COND(action_set.is_null());
+
+ action_map->add_action_set(action_set);
+ actionsets_vb->add_child(p_action_set_editor);
+}
+
+void OpenXRActionMapEditor::_do_remove_action_set_editor(OpenXRActionSetEditor *p_action_set_editor) {
+ Ref<OpenXRActionSet> action_set = p_action_set_editor->get_action_set();
+ ERR_FAIL_COND(action_set.is_null());
+
+ actionsets_vb->remove_child(p_action_set_editor);
+ action_map->remove_action_set(action_set);
+}
+
+void OpenXRActionMapEditor::_do_add_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor) {
+ Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profile_editor->get_interaction_profile();
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ action_map->add_interaction_profile(interaction_profile);
+ tabs->add_child(p_interaction_profile_editor);
+ tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
+
+ tabs->set_current_tab(tabs->get_tab_count() - 1);
+}
- Ref<OpenXRInteractionProfile> interaction_profile = profile_editor->get_interaction_profile();
+void OpenXRActionMapEditor::_do_remove_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor) {
+ Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profile_editor->get_interaction_profile();
ERR_FAIL_COND(interaction_profile.is_null());
+ tabs->remove_child(p_interaction_profile_editor);
action_map->remove_interaction_profile(interaction_profile);
- tabs->remove_child(profile_editor);
- profile_editor->queue_free();
}
void OpenXRActionMapEditor::open_action_map(String p_path) {
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+ // out with the old...
+ _clear_action_map();
+
+ // now load in our new action map
_load_action_map(p_path);
- _update_action_sets();
- _update_interaction_profiles();
+ _create_action_sets();
+ _create_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_clear_action_map() {
+ while (actionsets_vb->get_child_count() > 0) {
+ Node *child = actionsets_vb->get_child(0);
+ actionsets_vb->remove_child(child);
+ child->queue_free();
+ }
+
+ for (int i = 0; i < tabs->get_tab_count(); i++) {
+ // First tab won't be an interaction profile editor, but being thorough..
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(i));
+ if (interaction_profile_editor) {
+ tabs->remove_child(interaction_profile_editor);
+ interaction_profile_editor->queue_free();
+ }
+ }
}
OpenXRActionMapEditor::OpenXRActionMapEditor() {
+ undo_redo = EditorNode::get_undo_redo();
set_custom_minimum_size(Size2(0.0, 300.0));
top_hb = memnew(HBoxContainer);
@@ -364,7 +448,9 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() {
select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected));
add_child(select_interaction_profile_dialog);
- _load_action_map(GLOBAL_GET("xr/openxr/default_action_map"));
+ // Our Action map editor is only shown if openxr is enabled in project settings
+ // So load our action map and if it doesn't exist, create it right away.
+ _load_action_map(GLOBAL_GET("xr/openxr/default_action_map"), true);
}
OpenXRActionMapEditor::~OpenXRActionMapEditor() {
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
index a19bc90f56..8e3210a8e9 100644
--- a/modules/openxr/editor/openxr_action_map_editor.h
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -37,6 +37,7 @@
#include "../editor/openxr_select_interaction_profile_dialog.h"
#include "editor/editor_plugin.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
@@ -47,9 +48,9 @@ class OpenXRActionMapEditor : public VBoxContainer {
GDCLASS(OpenXRActionMapEditor, VBoxContainer);
private:
+ Ref<EditorUndoRedoManager> undo_redo;
String edited_path;
Ref<OpenXRActionMap> action_map;
- Vector<Node *> interaction_profiles;
HBoxContainer *top_hb = nullptr;
Label *header_label = nullptr;
@@ -64,9 +65,9 @@ private:
OpenXRSelectInteractionProfileDialog *select_interaction_profile_dialog = nullptr;
OpenXRActionSetEditor *_add_action_set_editor(Ref<OpenXRActionSet> p_action_set);
- void _update_action_sets();
+ void _create_action_sets();
OpenXRInteractionProfileEditorBase *_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile);
- void _update_interaction_profiles();
+ void _create_interaction_profiles();
OpenXRActionSetEditor *_add_action_set(String p_name);
void _remove_action_set(String p_name);
@@ -90,6 +91,14 @@ protected:
static void _bind_methods();
void _notification(int p_what);
+ void _clear_action_map();
+
+ // used for undo/redo
+ void _do_add_action_set_editor(OpenXRActionSetEditor *p_action_set_editor);
+ void _do_remove_action_set_editor(OpenXRActionSetEditor *p_action_set_editor);
+ void _do_add_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor);
+ void _do_remove_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor);
+
public:
void open_action_map(String p_path);
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index 3869146e8e..d3b6945635 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -32,8 +32,14 @@
#include "openxr_action_editor.h"
void OpenXRActionSetEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionSetEditor::_do_set_name);
+ ClassDB::bind_method(D_METHOD("_do_set_localized_name", "name"), &OpenXRActionSetEditor::_do_set_localized_name);
+ ClassDB::bind_method(D_METHOD("_do_set_priority", "value"), &OpenXRActionSetEditor::_do_set_priority);
+ ClassDB::bind_method(D_METHOD("_do_add_action_editor", "action_editor"), &OpenXRActionSetEditor::_do_add_action_editor);
+ ClassDB::bind_method(D_METHOD("_do_remove_action_editor", "action_editor"), &OpenXRActionSetEditor::_do_remove_action_editor);
+
ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_set_editor")));
- ADD_SIGNAL(MethodInfo("action_removed"));
+ ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::OBJECT, "action")));
}
void OpenXRActionSetEditor::_set_fold_icon() {
@@ -68,20 +74,6 @@ OpenXRActionEditor *OpenXRActionSetEditor::_add_action_editor(Ref<OpenXRAction>
return action_editor;
}
-void OpenXRActionSetEditor::_update_actions() {
- // out with the old...
- while (actions_vb->get_child_count() > 0) {
- memdelete(actions_vb->get_child(0));
- }
-
- // in with the new...
- Array actions = action_set->get_actions();
- for (int i = 0; i < actions.size(); i++) {
- Ref<OpenXRAction> action = actions[i];
- _add_action_editor(action);
- }
-}
-
void OpenXRActionSetEditor::_on_toggle_expand() {
is_expanded = !is_expanded;
actions_vb->set_visible(is_expanded);
@@ -89,24 +81,66 @@ void OpenXRActionSetEditor::_on_toggle_expand() {
}
void OpenXRActionSetEditor::_on_action_set_name_changed(const String p_new_text) {
- // TODO validate if entry is allowed
-
- // If our localized name matches our action set name, set this too
- if (action_set->get_name() == action_set->get_localized_name()) {
- action_set->set_localized_name(p_new_text);
- action_set_localized_name->set_text(p_new_text);
+ if (action_set->get_name() != p_new_text) {
+ undo_redo->create_action(TTR("Rename Action Set"));
+ undo_redo->add_do_method(this, "_do_set_name", p_new_text);
+ undo_redo->add_undo_method(this, "_do_set_name", action_set->get_name());
+ undo_redo->commit_action(false);
+
+ // If our localized name matches our action set name, set this too
+ if (action_set->get_name() == action_set->get_localized_name()) {
+ undo_redo->create_action(TTR("Rename Action Sets Localized name"));
+ undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
+ undo_redo->add_undo_method(this, "_do_set_localized_name", action_set->get_localized_name());
+ undo_redo->commit_action(false);
+
+ action_set->set_localized_name(p_new_text);
+ action_set_localized_name->set_text(p_new_text);
+ }
+ action_set->set_name(p_new_text);
+ action_set->set_edited(true);
}
+}
+
+void OpenXRActionSetEditor::_do_set_name(const String p_new_text) {
action_set->set_name(p_new_text);
+ action_set_name->set_text(p_new_text);
}
void OpenXRActionSetEditor::_on_action_set_localized_name_changed(const String p_new_text) {
+ if (action_set->get_localized_name() != p_new_text) {
+ undo_redo->create_action(TTR("Rename Action Sets Localized name"));
+ undo_redo->add_do_method(this, "_do_set_localized_name", p_new_text);
+ undo_redo->add_undo_method(this, "_do_set_localized_name", action_set->get_localized_name());
+ undo_redo->commit_action(false);
+
+ action_set->set_localized_name(p_new_text);
+ action_set->set_edited(true);
+ }
+}
+
+void OpenXRActionSetEditor::_do_set_localized_name(const String p_new_text) {
action_set->set_localized_name(p_new_text);
+ action_set_localized_name->set_text(p_new_text);
}
void OpenXRActionSetEditor::_on_action_set_priority_changed(const String p_new_text) {
int64_t value = p_new_text.to_int();
- action_set->set_priority(value);
+ if (action_set->get_priority() != value) {
+ undo_redo->create_action(TTR("Change Action Sets priority"));
+ undo_redo->add_do_method(this, "_do_set_priority", value);
+ undo_redo->add_undo_method(this, "_do_set_priority", action_set->get_priority());
+ undo_redo->commit_action(false);
+
+ action_set->set_priority(value);
+ action_set->set_edited(true);
+ }
+}
+
+void OpenXRActionSetEditor::_do_set_priority(int64_t p_value) {
+ action_set->set_priority(p_value);
+ action_set_priority->set_text(itos(p_value));
}
void OpenXRActionSetEditor::_on_add_action() {
@@ -116,8 +150,14 @@ void OpenXRActionSetEditor::_on_add_action() {
new_action->set_name("New");
new_action->set_localized_name("New");
action_set->add_action(new_action);
+ action_set->set_edited(true);
- _add_action_editor(new_action);
+ OpenXRActionEditor *action_editor = _add_action_editor(new_action);
+
+ undo_redo->create_action(TTR("Add action"));
+ undo_redo->add_do_method(this, "_do_add_action_editor", action_editor);
+ undo_redo->add_undo_method(this, "_do_remove_action_editor", action_editor);
+ undo_redo->commit_action(false);
// TODO handle focus
}
@@ -133,17 +173,36 @@ void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) {
Ref<OpenXRAction> action = action_editor->get_action();
ERR_FAIL_COND(action.is_null());
- // TODO add undo/redo action
+ emit_signal("action_removed", action);
+
+ undo_redo->create_action(TTR("Delete action"));
+ undo_redo->add_do_method(this, "_do_remove_action_editor", action_editor);
+ undo_redo->add_undo_method(this, "_do_add_action_editor", action_editor);
+ undo_redo->commit_action(true);
- // TODO find where this action is used by our interaction profiles and remove it there
+ action_set->set_edited(true);
+}
- // And remove it....
- action_map->remove_action(action->get_name_with_set()); // remove it from the set and any interaction profile it relates to
- actions_vb->remove_child(action_editor);
- action_editor->queue_free();
+void OpenXRActionSetEditor::_do_add_action_editor(OpenXRActionEditor *p_action_editor) {
+ Ref<OpenXRAction> action = p_action_editor->get_action();
+ ERR_FAIL_COND(action.is_null());
- // Let action map editor know so we can update our interaction profiles
- emit_signal("action_removed");
+ action_set->add_action(action);
+ actions_vb->add_child(p_action_editor);
+}
+
+void OpenXRActionSetEditor::_do_remove_action_editor(OpenXRActionEditor *p_action_editor) {
+ Ref<OpenXRAction> action = p_action_editor->get_action();
+ ERR_FAIL_COND(action.is_null());
+
+ actions_vb->remove_child(p_action_editor);
+ action_set->remove_action(action);
+}
+
+void OpenXRActionSetEditor::remove_all_actions() {
+ for (int i = actions_vb->get_child_count(); i > 0; --i) {
+ _on_remove_action(actions_vb->get_child(i));
+ }
}
void OpenXRActionSetEditor::set_focus_on_entry() {
@@ -214,5 +273,10 @@ OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map,
actions_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
main_vb->add_child(actions_vb);
- _update_actions();
+ // Add our existing actions
+ Array actions = action_set->get_actions();
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ _add_action_editor(action);
+ }
}
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
index d8c85d03dd..7a8dc0dcbf 100644
--- a/modules/openxr/editor/openxr_action_set_editor.h
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -44,6 +44,7 @@ class OpenXRActionSetEditor : public HBoxContainer {
GDCLASS(OpenXRActionSetEditor, HBoxContainer);
private:
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<OpenXRActionMap> action_map;
Ref<OpenXRActionSet> action_set;
@@ -63,7 +64,6 @@ private:
void _set_fold_icon();
void _theme_changed();
OpenXRActionEditor *_add_action_editor(Ref<OpenXRAction> p_action);
- void _update_actions();
void _on_toggle_expand();
void _on_action_set_name_changed(const String p_new_text);
@@ -78,10 +78,19 @@ protected:
static void _bind_methods();
void _notification(int p_what);
+ // used for undo/redo
+ void _do_set_name(const String p_new_text);
+ void _do_set_localized_name(const String p_new_text);
+ void _do_set_priority(int64_t value);
+ void _do_add_action_editor(OpenXRActionEditor *p_action_editor);
+ void _do_remove_action_editor(OpenXRActionEditor *p_action_editor);
+
public:
Ref<OpenXRActionSet> get_action_set() { return action_set; };
void set_focus_on_entry();
+ void remove_all_actions();
+
OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set);
};
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
index e2dc2d1b74..3eca1967f5 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "openxr_interaction_profile_editor.h"
+#include "editor/editor_node.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
@@ -58,6 +59,13 @@ void OpenXRInteractionProfileEditorBase::_notification(int p_what) {
}
}
+void OpenXRInteractionProfileEditorBase::_do_update_interaction_profile() {
+ if (!is_dirty) {
+ is_dirty = true;
+ call_deferred("_update_interaction_profile");
+ }
+}
+
void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, const String p_path) {
ERR_FAIL_COND(action_map.is_null());
ERR_FAIL_COND(interaction_profile.is_null());
@@ -71,14 +79,16 @@ void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, con
binding.instantiate();
binding->set_action(action);
interaction_profile->add_binding(binding);
+ interaction_profile->set_edited(true);
}
binding->add_path(p_path);
+ binding->set_edited(true);
// Update our toplevel paths
action->set_toplevel_paths(action_map->get_top_level_paths(action));
- call_deferred("_update_interaction_profile");
+ _do_update_interaction_profile();
}
void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, const String p_path) {
@@ -91,25 +101,54 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action,
Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
if (binding.is_valid()) {
binding->remove_path(p_path);
+ binding->set_edited(true);
if (binding->get_path_count() == 0) {
interaction_profile->remove_binding(binding);
+ interaction_profile->set_edited(true);
}
// Update our toplevel paths
action->set_toplevel_paths(action_map->get_top_level_paths(action));
- call_deferred("_update_interaction_profile");
+ _do_update_interaction_profile();
+ }
+}
+
+void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<OpenXRAction> p_action) {
+ Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(p_action);
+ if (binding.is_valid()) {
+ String action_name = p_action->get_name_with_set();
+
+ // for our undo/redo we process all paths
+ undo_redo->create_action(TTR("Remove action from interaction profile"));
+ PackedStringArray paths = binding->get_paths();
+ for (const String &path : paths) {
+ undo_redo->add_do_method(this, "_remove_binding", p_action, path);
+ undo_redo->add_undo_method(this, "_add_binding", p_action, path);
+ }
+ undo_redo->commit_action(false);
+
+ // but we take a shortcut here :)
+ interaction_profile->remove_binding(binding);
+ interaction_profile->set_edited(true);
+
+ // Update our toplevel paths
+ p_action->set_toplevel_paths(action_map->get_top_level_paths(p_action));
+
+ _do_update_interaction_profile();
}
}
OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
+ undo_redo = EditorNode::get_undo_redo();
+
action_map = p_action_map;
interaction_profile = p_interaction_profile;
String profile_path = interaction_profile->get_interaction_profile_path();
String profile_name = profile_path;
- profile_def = OpenXRDefs::get_profile(profile_path);
+ profile_def = OpenXRInteractionProfileMetaData::get_singleton()->get_profile(profile_path);
if (profile_def != nullptr) {
profile_name = profile_def->display_name;
}
@@ -117,6 +156,9 @@ OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenX
set_name(profile_name);
set_h_size_flags(SIZE_EXPAND_FILL);
set_v_size_flags(SIZE_EXPAND_FILL);
+
+ // Make sure it is updated when it enters the tree...
+ is_dirty = true;
}
///////////////////////////////////////////////////////////////////////////
@@ -128,11 +170,22 @@ void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) {
}
void OpenXRInteractionProfileEditor::action_selected(const String p_action) {
- _add_binding(p_action, selecting_for_io_path);
+ undo_redo->create_action(TTR("Add binding"));
+ undo_redo->add_do_method(this, "_add_binding", p_action, selecting_for_io_path);
+ undo_redo->add_undo_method(this, "_remove_binding", p_action, selecting_for_io_path);
+ undo_redo->commit_action(true);
+
selecting_for_io_path = "";
}
-void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path) {
+void OpenXRInteractionProfileEditor::_on_remove_pressed(const String p_action, const String p_for_io_path) {
+ undo_redo->create_action(TTR("Remove binding"));
+ undo_redo->add_do_method(this, "_remove_binding", p_action, p_for_io_path);
+ undo_redo->add_undo_method(this, "_add_binding", p_action, p_for_io_path);
+ undo_redo->commit_action(true);
+}
+
+void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetaData::IOPath *p_io_path) {
HBoxContainer *path_hb = memnew(HBoxContainer);
path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
p_container->add_child(path_hb);
@@ -196,7 +249,7 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co
Button *action_rem = memnew(Button);
action_rem->set_flat(true);
action_rem->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditorBase *)this, &OpenXRInteractionProfileEditorBase::_remove_binding).bind(action->get_name_with_set(), String(p_io_path->openxr_path)));
+ action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditor *)this, &OpenXRInteractionProfileEditor::_on_remove_pressed).bind(action->get_name_with_set(), String(p_io_path->openxr_path)));
action_hb->add_child(action_rem);
}
}
@@ -206,6 +259,11 @@ void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, co
void OpenXRInteractionProfileEditor::_update_interaction_profile() {
ERR_FAIL_NULL(profile_def);
+ if (!is_dirty) {
+ // no need to update
+ return;
+ }
+
// out with the old...
while (main_hb->get_child_count() > 0) {
memdelete(main_hb->get_child(0));
@@ -214,9 +272,9 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
// in with the new...
// Determine toplevel paths
- Vector<const OpenXRDefs::TopLevelPath *> top_level_paths;
- for (int i = 0; i < profile_def->io_path_count; i++) {
- const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[i];
+ Vector<String> top_level_paths;
+ for (int i = 0; i < profile_def->io_paths.size(); i++) {
+ const OpenXRInteractionProfileMetaData::IOPath *io_path = &profile_def->io_paths[i];
if (!top_level_paths.has(io_path->top_level_path)) {
top_level_paths.push_back(io_path->top_level_path);
@@ -233,16 +291,19 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
panel->add_child(container);
Label *label = memnew(Label);
- label->set_text(top_level_paths[i]->display_name);
+ label->set_text(OpenXRInteractionProfileMetaData::get_singleton()->get_top_level_name(top_level_paths[i]));
container->add_child(label);
- for (int j = 0; j < profile_def->io_path_count; j++) {
- const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[j];
+ for (int j = 0; j < profile_def->io_paths.size(); j++) {
+ const OpenXRInteractionProfileMetaData::IOPath *io_path = &profile_def->io_paths[j];
if (io_path->top_level_path == top_level_paths[i]) {
_add_io_path(container, io_path);
}
}
}
+
+ // and we've updated it...
+ is_dirty = false;
}
void OpenXRInteractionProfileEditor::_theme_changed() {
@@ -256,14 +317,10 @@ void OpenXRInteractionProfileEditor::_theme_changed() {
OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) :
OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) {
- // TODO background of scrollbox should be darker with our VBoxContainers we're adding in _update_interaction_profile the normal color
-
main_hb = memnew(HBoxContainer);
add_child(main_hb);
select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map));
select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected));
add_child(select_action_dialog);
-
- _update_interaction_profile();
}
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
index 20a37a80eb..14af702b94 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.h
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -32,8 +32,9 @@
#define OPENXR_INTERACTION_PROFILE_EDITOR_H
#include "../action_map/openxr_action_map.h"
-#include "../action_map/openxr_defs.h"
#include "../action_map/openxr_interaction_profile.h"
+#include "../action_map/openxr_interaction_profile_meta_data.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/scroll_container.h"
#include "openxr_select_action_dialog.h"
@@ -42,22 +43,29 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer {
GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
protected:
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<OpenXRInteractionProfile> interaction_profile;
Ref<OpenXRActionMap> action_map;
+ bool is_dirty = false;
+
static void _bind_methods();
void _notification(int p_what);
- const OpenXRDefs::InteractionProfile *profile_def = nullptr;
+ const OpenXRInteractionProfileMetaData::InteractionProfile *profile_def = nullptr;
public:
Ref<OpenXRInteractionProfile> get_interaction_profile() { return interaction_profile; }
virtual void _update_interaction_profile() {}
virtual void _theme_changed() {}
+
+ void _do_update_interaction_profile();
void _add_binding(const String p_action, const String p_path);
void _remove_binding(const String p_action, const String p_path);
+ void remove_all_bindings_for_action(Ref<OpenXRAction> p_action);
+
OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
};
@@ -69,11 +77,12 @@ private:
HBoxContainer *main_hb = nullptr;
OpenXRSelectActionDialog *select_action_dialog = nullptr;
- void _add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path);
+ void _add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetaData::IOPath *p_io_path);
public:
void select_action_for(const String p_io_path);
void action_selected(const String p_action);
+ void _on_remove_pressed(const String p_action, const String p_for_io_path);
virtual void _update_interaction_profile() override;
virtual void _theme_changed() override;
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
index e92519aec2..6ce26a62db 100644
--- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
@@ -75,13 +75,13 @@ void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_inclu
ip_buttons.clear();
// in with the new
- PackedStringArray interaction_profiles = OpenXRDefs::get_interaction_profile_paths();
+ PackedStringArray interaction_profiles = OpenXRInteractionProfileMetaData::get_singleton()->get_interaction_profile_paths();
for (int i = 0; i < interaction_profiles.size(); i++) {
String path = interaction_profiles[i];
if (!p_do_not_include.has(path)) {
Button *ip_button = memnew(Button);
ip_button->set_flat(true);
- ip_button->set_text(OpenXRDefs::get_profile(path)->display_name);
+ ip_button->set_text(OpenXRInteractionProfileMetaData::get_singleton()->get_profile(path)->display_name);
ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile).bind(path));
main_vb->add_child(ip_button);
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
index 54bfe3120a..767326bc46 100644
--- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
@@ -31,7 +31,7 @@
#ifndef OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
-#include "../action_map/openxr_defs.h"
+#include "../action_map/openxr_interaction_profile_meta_data.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp
index 753fc5fa89..402a2ee707 100644
--- a/modules/openxr/extensions/openxr_android_extension.cpp
+++ b/modules/openxr/extensions/openxr_android_extension.cpp
@@ -74,7 +74,7 @@ void OpenXRAndroidExtension::on_before_instance_created() {
}
// We're keeping the Android create info struct here to avoid including openxr_platform.h in a header, which would break other extensions.
-// This is reasonably safe as the struct is only used during intialization and the extension is a singleton.
+// This is reasonably safe as the struct is only used during initialization and the extension is a singleton.
static XrInstanceCreateInfoAndroidKHR instance_create_info;
void *OpenXRAndroidExtension::set_instance_create_info_and_get_next_pointer(void *p_next_pointer) {
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 77b52ab355..eed969d628 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -89,11 +89,6 @@ public:
return false;
}
- // Return false if this extension is responsible for this path but the path is not enabled
- virtual bool is_path_supported(const String &p_path) {
- return true;
- }
-
OpenXRExtensionWrapper(OpenXRAPI *p_openxr_api) { openxr_api = p_openxr_api; };
virtual ~OpenXRExtensionWrapper() = default;
};
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
index 29208efb20..302acf4e30 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
@@ -65,38 +65,3 @@ bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &eve
} break;
}
}
-
-bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) {
- if (p_path == "/interaction_profiles/htc/vive_tracker_htcx") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/handheld_object") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/left_foot") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/right_foot") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/left_shoulder") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/right_shoulder") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/left_elbow") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/right_elbow") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/left_knee") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/right_knee") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/waist") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/camera") {
- return available;
- } else if (p_path == "/user/vive_tracker_htcx/role/keyboard") {
- return available;
- }
-
- // Not a path under this extensions control, so we return true;
- return true;
-}
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h
index ab8e8535f1..376af35e37 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h
@@ -43,7 +43,6 @@ public:
bool is_available();
virtual bool on_event_polled(const XrEventDataBuffer &event) override;
- virtual bool is_path_supported(const String &p_path) override;
private:
static OpenXRHTCViveTrackerExtension *singleton;
diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.cpp b/modules/openxr/extensions/openxr_palm_pose_extension.cpp
index fd3b8f50fe..8f87aaea7f 100644
--- a/modules/openxr/extensions/openxr_palm_pose_extension.cpp
+++ b/modules/openxr/extensions/openxr_palm_pose_extension.cpp
@@ -51,16 +51,3 @@ OpenXRPalmPoseExtension::~OpenXRPalmPoseExtension() {
bool OpenXRPalmPoseExtension::is_available() {
return available;
}
-
-bool OpenXRPalmPoseExtension::is_path_supported(const String &p_path) {
- if (p_path == "/user/hand/left/input/palm_ext/pose") {
- return available;
- }
-
- if (p_path == "/user/hand/right/input/palm_ext/pose") {
- return available;
- }
-
- // Not a path under this extensions control, so we return true;
- return true;
-}
diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.h b/modules/openxr/extensions/openxr_palm_pose_extension.h
index a7ef83c5d5..a63c57eb51 100644
--- a/modules/openxr/extensions/openxr_palm_pose_extension.h
+++ b/modules/openxr/extensions/openxr_palm_pose_extension.h
@@ -42,8 +42,6 @@ public:
bool is_available();
- virtual bool is_path_supported(const String &p_path) override;
-
private:
static OpenXRPalmPoseExtension *singleton;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 71e1d9c351..a075031ac9 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -208,17 +208,79 @@ bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
return false;
}
-bool OpenXRAPI::is_path_supported(const String &p_path) {
- // This checks with extensions whether a path is *unsupported* and returns false if this is so.
- // This allows us to filter out paths that are only available if related extensions are supported.
- // WARNING: This method will return true for unknown/mistyped paths as we have no way to validate those.
+bool OpenXRAPI::is_extension_enabled(const String &p_extension) const {
+ CharString extension = p_extension.ascii();
- for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
- if (!wrapper->is_path_supported(p_path)) {
- return false;
+ for (int i = 0; i < enabled_extensions.size(); i++) {
+ if (strcmp(enabled_extensions[i].ptr(), extension.ptr()) == 0) {
+ return true;
}
}
+ return false;
+}
+
+bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) {
+ String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_top_level_extension(p_toplevel_path);
+
+ // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error.
+ ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_toplevel_path);
+
+ if (required_extension == "") {
+ // no extension needed, core top level are always "supported", they just won't be used if not really supported
+ return true;
+ }
+
+ if (!is_extension_enabled(required_extension)) {
+ // It is very likely we have top level paths for which the extension is not available so don't flood the logs with unnecessary spam.
+ print_verbose("OpenXR: Top level path " + p_toplevel_path + " requires extension " + required_extension);
+ return false;
+ }
+
+ return true;
+}
+
+bool OpenXRAPI::is_interaction_profile_supported(const String &p_ip_path) {
+ String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_interaction_profile_extension(p_ip_path);
+
+ // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error.
+ ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_ip_path);
+
+ if (required_extension == "") {
+ // no extension needed, core interaction profiles are always "supported", they just won't be used if not really supported
+ return true;
+ }
+
+ if (!is_extension_enabled(required_extension)) {
+ // It is very likely we have interaction profiles for which the extension is not available so don't flood the logs with unnecessary spam.
+ print_verbose("OpenXR: Interaction profile " + p_ip_path + " requires extension " + required_extension);
+ return false;
+ }
+
+ return true;
+}
+
+bool OpenXRAPI::interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path) {
+ if (!is_interaction_profile_supported(p_ip_path)) {
+ return false;
+ }
+
+ const OpenXRInteractionProfileMetaData::IOPath *io_path = OpenXRInteractionProfileMetaData::get_singleton()->get_io_path(p_ip_path, p_io_path);
+
+ // If the io_path is not part of our meta data we've likely got a misspelled name or a bad action map, report
+ ERR_FAIL_NULL_V_MSG(io_path, false, "OpenXR: Unsupported io path " + String(p_ip_path) + String(p_io_path));
+
+ if (io_path->openxr_extension_name == "") {
+ // no extension needed, core io paths are always "supported", they just won't be used if not really supported
+ return true;
+ }
+
+ if (!is_extension_enabled(io_path->openxr_extension_name)) {
+ // It is very likely we have io paths for which the extension is not available so don't flood the logs with unnecessary spam.
+ print_verbose("OpenXR: IO path " + String(p_ip_path) + String(p_io_path) + " requires extension " + io_path->openxr_extension_name);
+ return false;
+ }
+
return true;
}
@@ -283,6 +345,7 @@ bool OpenXRAPI::create_instance() {
Vector<const char *> extension_ptrs;
for (int i = 0; i < enabled_extensions.size(); i++) {
+ print_verbose(String("OpenXR: Enabling extension ") + String(enabled_extensions[i]));
extension_ptrs.push_back(enabled_extensions[i].get_data());
}
@@ -740,9 +803,10 @@ bool OpenXRAPI::create_swapchains() {
ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views");
// We create our depth swapchain if:
+ // - we've enabled submitting depth buffer
// - we support our depth layer extension
// - we have our spacewarp extension (not yet implemented)
- if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
+ if (submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
// Build a vector with swapchain formats we want to use, from best fit to worst
Vector<int64_t> usable_swapchain_formats;
int64_t swapchain_format_to_use = 0;
@@ -790,7 +854,7 @@ bool OpenXRAPI::create_swapchains() {
projection_views[i].subImage.imageRect.extent.width = recommended_size.width;
projection_views[i].subImage.imageRect.extent.height = recommended_size.height;
- if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) {
+ if (submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) {
projection_views[i].next = &depth_views[i];
depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
@@ -1066,6 +1130,30 @@ bool OpenXRAPI::on_state_exiting() {
return true;
}
+void OpenXRAPI::set_form_factor(XrFormFactor p_form_factor) {
+ ERR_FAIL_COND(is_initialized());
+
+ form_factor = p_form_factor;
+}
+
+void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configuration) {
+ ERR_FAIL_COND(is_initialized());
+
+ view_configuration = p_view_configuration;
+}
+
+void OpenXRAPI::set_reference_space(XrReferenceSpaceType p_reference_space) {
+ ERR_FAIL_COND(is_initialized());
+
+ reference_space = p_reference_space;
+}
+
+void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) {
+ ERR_FAIL_COND(is_initialized());
+
+ submit_depth_buffer = p_submit_depth_buffer;
+}
+
bool OpenXRAPI::is_initialized() {
return (instance != XR_NULL_HANDLE);
}
@@ -1684,7 +1772,7 @@ RID OpenXRAPI::get_color_texture() {
}
RID OpenXRAPI::get_depth_texture() {
- if (swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) {
+ if (submit_depth_buffer && swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) {
return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_DEPTH].image_index);
} else {
return RID();
@@ -1862,6 +1950,8 @@ OpenXRAPI::OpenXRAPI() {
default:
break;
}
+
+ submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer");
}
// reset a few things that can't be done in our class definition
@@ -2314,7 +2404,7 @@ XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) {
}
RID OpenXRAPI::interaction_profile_create(const String p_name) {
- if (!is_path_supported(p_name)) {
+ if (!is_interaction_profile_supported(p_name)) {
// The extension enabling this path must not be active, we will silently skip this interaction profile
return RID();
}
@@ -2355,14 +2445,13 @@ void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) {
}
bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {
- if (!is_path_supported(p_path)) {
- // The extension enabling this path must not be active, we will silently skip this binding
- return false;
- }
-
InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
ERR_FAIL_NULL_V(ip, false);
+ if (!interaction_profile_supports_io_path(ip->name, p_path)) {
+ return false;
+ }
+
XrActionSuggestedBinding binding;
Action *action = action_owner.get_or_null(p_action);
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 5dce749351..806e859da0 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -104,6 +104,7 @@ private:
XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
// XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
+ bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled.
// state
XrInstance instance = XR_NULL_HANDLE;
@@ -149,6 +150,7 @@ private:
bool load_layer_properties();
bool load_supported_extensions();
bool is_extension_supported(const String &p_extension) const;
+ bool is_extension_enabled(const String &p_extension) const;
bool openxr_loader_init();
bool resolve_instance_openxr_symbols();
@@ -300,7 +302,9 @@ public:
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
bool xr_result(XrResult result, const char *format, Array args = Array()) const;
- bool is_path_supported(const String &p_path);
+ bool is_top_level_path_supported(const String &p_toplevel_path);
+ bool is_interaction_profile_supported(const String &p_ip_path);
+ bool interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path);
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
@@ -312,6 +316,18 @@ public:
void set_xr_interface(OpenXRInterface *p_xr_interface);
void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
+ void set_form_factor(XrFormFactor p_form_factor);
+ XrFormFactor get_form_factor() const { return form_factor; }
+
+ void set_view_configuration(XrViewConfigurationType p_view_configuration);
+ XrViewConfigurationType get_view_configuration() const { return view_configuration; }
+
+ void set_reference_space(XrReferenceSpaceType p_reference_space);
+ XrReferenceSpaceType get_reference_space() const { return reference_space; }
+
+ void set_submit_depth_buffer(bool p_submit_depth_buffer);
+ bool get_submit_depth_buffer() const { return submit_depth_buffer; }
+
bool is_initialized();
bool is_running();
bool initialize(const String &p_rendering_driver);
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 77660eb6f0..d6f7cd7b3e 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -45,7 +45,7 @@ void OpenXRInterface::_bind_methods() {
// Display refresh rate
ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate);
ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "display_refresh_rate"), "set_display_refresh_rate", "get_display_refresh_rate");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "display_refresh_rate"), "set_display_refresh_rate", "get_display_refresh_rate");
ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
}
@@ -158,7 +158,7 @@ void OpenXRInterface::_load_action_map() {
for (int k = 0; k < toplevel_paths.size(); k++) {
// Only check for our tracker if our path is supported.
- if (openxr_api->is_path_supported(toplevel_paths[k])) {
+ if (openxr_api->is_top_level_path_supported(toplevel_paths[k])) {
Tracker *tracker = find_tracker(toplevel_paths[k], true);
if (tracker) {
trackers_for_action.push_back(tracker);
@@ -345,7 +345,7 @@ OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_
return nullptr;
}
- ERR_FAIL_COND_V(!openxr_api->is_path_supported(p_tracker_name), nullptr);
+ ERR_FAIL_COND_V(!openxr_api->is_top_level_path_supported(p_tracker_name), nullptr);
// Create our RID
RID tracker_rid = openxr_api->tracker_create(p_tracker_name);
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 5694fffe39..0835bbd642 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -37,9 +37,14 @@
#include "action_map/openxr_action_map.h"
#include "action_map/openxr_action_set.h"
#include "action_map/openxr_interaction_profile.h"
+#include "action_map/openxr_interaction_profile_meta_data.h"
#include "scene/openxr_hand.h"
+static OpenXRAPI *openxr_api = nullptr;
+static OpenXRInteractionProfileMetaData *openxr_interaction_profile_meta_data = nullptr;
+static Ref<OpenXRInterface> openxr_interface;
+
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
@@ -49,6 +54,12 @@ static void _editor_init() {
if (OpenXRAPI::openxr_is_enabled(false)) {
// Only add our OpenXR action map editor if OpenXR is enabled for our project
+ if (openxr_interaction_profile_meta_data == nullptr) {
+ // If we didn't initialize our actionmap meta data at startup, we initialise it now.
+ openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData);
+ ERR_FAIL_NULL(openxr_interaction_profile_meta_data);
+ }
+
OpenXREditorPlugin *openxr_plugin = memnew(OpenXREditorPlugin());
EditorNode::get_singleton()->add_editor_plugin(openxr_plugin);
}
@@ -56,14 +67,13 @@ static void _editor_init() {
#endif
-static OpenXRAPI *openxr_api = nullptr;
-static Ref<OpenXRInterface> openxr_interface;
-
void initialize_openxr_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
// For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon.
if (OpenXRAPI::openxr_is_enabled()) {
+ openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData);
+ ERR_FAIL_NULL(openxr_interaction_profile_meta_data);
openxr_api = memnew(OpenXRAPI);
ERR_FAIL_NULL(openxr_api);
@@ -81,6 +91,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(OpenXRAction);
GDREGISTER_CLASS(OpenXRActionSet);
GDREGISTER_CLASS(OpenXRActionMap);
+ GDREGISTER_CLASS(OpenXRInteractionProfileMetaData);
GDREGISTER_CLASS(OpenXRIPBinding);
GDREGISTER_CLASS(OpenXRInteractionProfile);
@@ -131,4 +142,9 @@ void uninitialize_openxr_module(ModuleInitializationLevel p_level) {
memdelete(openxr_api);
openxr_api = nullptr;
}
+
+ if (openxr_interaction_profile_meta_data) {
+ memdelete(openxr_interaction_profile_meta_data);
+ openxr_interaction_profile_meta_data = nullptr;
+ }
}
diff --git a/modules/raycast/config.py b/modules/raycast/config.py
index f4243f01c5..26329d813a 100644
--- a/modules/raycast/config.py
+++ b/modules/raycast/config.py
@@ -1,13 +1,11 @@
def can_build(env, platform):
# Supported architectures depend on the Embree library.
- # No ARM32 support planned.
- if env["arch"] == "arm32":
- return False
+ if env["arch"] in ["x86_64", "arm64", "wasm32"]:
+ return True
# x86_32 only seems supported on Windows for now.
- if env["arch"] == "x86_32" and platform != "windows":
- return False
- # The rest works, even wasm32!
- return True
+ if env["arch"] == "x86_32" and platform == "windows":
+ return True
+ return False
def configure(env):
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index c808211d68..6f02d20c25 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -50,8 +50,7 @@ int RegExMatch::_find(const Variant &p_name) const {
return -1;
}
return i;
-
- } else if (p_name.get_type() == Variant::STRING) {
+ } else if (p_name.get_type() == Variant::STRING || p_name.get_type() == Variant::STRING_NAME) {
HashMap<String, int>::ConstIterator found = names.find((String)p_name);
if (found) {
return found->value;
diff --git a/modules/register_module_types.h b/modules/register_module_types.h
index cfd1b355d4..706e641735 100644
--- a/modules/register_module_types.h
+++ b/modules/register_module_types.h
@@ -31,13 +31,13 @@
#ifndef REGISTER_MODULE_TYPES_H
#define REGISTER_MODULE_TYPES_H
-#include "core/extension/gdnative_interface.h"
+#include "core/extension/gdextension_interface.h"
enum ModuleInitializationLevel {
- MODULE_INITIALIZATION_LEVEL_CORE = GDNATIVE_INITIALIZATION_CORE,
- MODULE_INITIALIZATION_LEVEL_SERVERS = GDNATIVE_INITIALIZATION_SERVERS,
- MODULE_INITIALIZATION_LEVEL_SCENE = GDNATIVE_INITIALIZATION_SCENE,
- MODULE_INITIALIZATION_LEVEL_EDITOR = GDNATIVE_INITIALIZATION_EDITOR
+ MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
+ MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
+ MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
+ MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
};
void initialize_modules(ModuleInitializationLevel p_level);
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 3c7a89b705..4a9c7b3567 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -223,9 +223,6 @@ if env["builtin_graphite"] and freetype_enabled and env["graphite"]:
]
)
- if env.msvc: # Not our business to fix.
- env_graphite.Append(CCFLAGS=["-D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS"])
-
lib = env_graphite.add_library("graphite_builtin", thirdparty_sources)
thirdparty_obj += lib
diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp
index 6a26584506..64373e9f2b 100644
--- a/modules/text_server_adv/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -62,7 +62,7 @@ using namespace godot;
extern "C" {
-GDNativeBool GDN_EXPORT textserver_advanced_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
+GDExtensionBool GDN_EXPORT textserver_advanced_init(const GDExtensionInterface *p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
init_obj.register_initializer(&initialize_text_server_adv_module);
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 27fab88956..512643867b 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -2151,10 +2151,7 @@ void TextServerAdvanced::_font_set_allow_system_fallback(const RID &p_font_rid,
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->allow_system_fallback != p_allow_system_fallback) {
- _font_clear_cache(fd);
- fd->allow_system_fallback = p_allow_system_fallback;
- }
+ fd->allow_system_fallback = p_allow_system_fallback;
}
bool TextServerAdvanced::_font_is_allow_system_fallback(const RID &p_font_rid) const {
@@ -6199,6 +6196,9 @@ String TextServerAdvanced::_strip_diacritics(const String &p_string) const {
}
String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const {
+ if (p_string.is_empty()) {
+ return p_string;
+ }
const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
// Convert to UTF-16.
@@ -6218,6 +6218,9 @@ String TextServerAdvanced::_string_to_upper(const String &p_string, const String
}
String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const {
+ if (p_string.is_empty()) {
+ return p_string;
+ }
const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
// Convert to UTF-16.
Char16String utf16 = p_string.utf16();
diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp
index fa7b87fc17..98a8f466b3 100644
--- a/modules/text_server_fb/register_types.cpp
+++ b/modules/text_server_fb/register_types.cpp
@@ -62,7 +62,7 @@ using namespace godot;
extern "C" {
-GDNativeBool GDN_EXPORT textserver_fallback_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
+GDExtensionBool GDN_EXPORT textserver_fallback_init(const GDExtensionInterface *p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
init_obj.register_initializer(&initialize_text_server_fb_module);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 9133c277bb..353d370f14 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -1246,10 +1246,7 @@ void TextServerFallback::_font_set_allow_system_fallback(const RID &p_font_rid,
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->allow_system_fallback != p_allow_system_fallback) {
- _font_clear_cache(fd);
- fd->allow_system_fallback = p_allow_system_fallback;
- }
+ fd->allow_system_fallback = p_allow_system_fallback;
}
bool TextServerFallback::_font_is_allow_system_fallback(const RID &p_font_rid) const {
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
index a9ba8a23de..a186631ca8 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
@@ -22,8 +22,8 @@
<method name="get_id" qualifiers="const">
<return type="int" />
<description>
- Returns the id assigned to this channel during creation (or auto-assigned during negotiation).
- If the channel is not negotiated out-of-band the id will only be available after the connection is established (will return [code]65535[/code] until then).
+ Returns the ID assigned to this channel during creation (or auto-assigned during negotiation).
+ If the channel is not negotiated out-of-band the ID will only be available after the connection is established (will return [code]65535[/code] until then).
</description>
</method>
<method name="get_label" qualifiers="const">
diff --git a/modules/webrtc/webrtc_data_channel_extension.h b/modules/webrtc/webrtc_data_channel_extension.h
index 467163ed93..92bd9619ef 100644
--- a/modules/webrtc/webrtc_data_channel_extension.h
+++ b/modules/webrtc/webrtc_data_channel_extension.h
@@ -70,8 +70,8 @@ public:
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
/** GDExtension **/
- GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
- GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int);
+ GDVIRTUAL2R(Error, _get_packet, GDExtensionConstPtr<const uint8_t *>, GDExtensionPtr<int>);
+ GDVIRTUAL2R(Error, _put_packet, GDExtensionConstPtr<const uint8_t>, int);
WebRTCDataChannelExtension() {}
};