diff options
Diffstat (limited to 'modules')
143 files changed, 4015 insertions, 918 deletions
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index 4c2ebe603f..18554177d9 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -244,7 +244,7 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format); if (!ret) { - printf("failed! on level %i\n", i); + printf("failed! on level %u\n", i); break; }; diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index ad2c7d6a3e..8813c3827a 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -200,8 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, return err; } -Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, - bool p_force_linear, float p_scale) { +Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { bmp_header_s bmp_header; Error err = ERR_INVALID_DATA; @@ -241,7 +240,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, case BI_CMYKRLE8: case BI_CMYKRLE4: { // Stop parsing. - f->close(); ERR_FAIL_V_MSG(ERR_UNAVAILABLE, vformat("Compressed BMP files are not supported: %s", f->get_path())); } break; @@ -283,7 +281,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, err = convert_to_image(p_image, bmp_buffer_r, bmp_color_table_r, color_table_size, bmp_header); } - f->close(); } } return err; @@ -294,12 +291,14 @@ void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const } static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) { - FileAccessMemory memfile; - Error open_memfile_error = memfile.open_custom(p_bmp, p_size); + Ref<FileAccessMemory> memfile; + memfile.instantiate(); + Error open_memfile_error = memfile->open_custom(p_bmp, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer."); + Ref<Image> img; img.instantiate(); - Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f); + Error load_error = ImageLoaderBMP().load_image(img, memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image."); return img; } diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h index 9c9a16a9f5..63dee0a969 100644 --- a/modules/bmp/image_loader_bmp.h +++ b/modules/bmp/image_loader_bmp.h @@ -83,8 +83,7 @@ protected: const bmp_header_s &p_header); public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, - bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderBMP(); }; diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 4721d0c11c..b5d5f97cf3 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -368,7 +368,7 @@ private: PathRotation path_rotation; bool path_local; - Path3D *path; + Path3D *path = nullptr; bool smooth_faces; bool path_continuous_u; diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 7bfe849106..58e5e31f46 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -100,12 +100,12 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, } Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { return RES(); } - FileAccessRef fref(f); + Ref<FileAccess> fref(f); if (r_error) { *r_error = ERR_FILE_CORRUPT; } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 3a0e320e9b..59254fc3ad 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -92,6 +92,21 @@ Object *GDScriptNativeClass::instantiate() { return ClassDB::instantiate(name); } +Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_method == SNAME("new")) { + // Constructor. + return Object::callp(p_method, p_args, p_argcount, r_error); + } + MethodBind *method = ClassDB::get_method(name, p_method); + if (method) { + // Native static method. + return method->call(nullptr, p_args, p_argcount, r_error); + } + + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); +} + GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) { if (p_script->initializer) { return p_script->initializer; @@ -1015,7 +1030,7 @@ Error GDScript::load_byte_code(const String &p_path) { Error GDScript::load_source_code(const String &p_path) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { ERR_FAIL_COND_V(err, err); } @@ -1024,8 +1039,6 @@ Error GDScript::load_source_code(const String &p_path) { sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; @@ -2084,7 +2097,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { Vector<uint8_t> sourcef; Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { return String(); } @@ -2118,8 +2131,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } else { Vector<StringName> extend_classes = subclass->extends; - FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ); - if (!subfile) { + Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ); + if (subfile.is_null()) { break; } String subsource = subfile->get_as_utf8_string(); @@ -2316,8 +2329,8 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con } void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'."); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'."); String source = file->get_as_utf8_string(); if (source.is_empty()) { @@ -2340,18 +2353,17 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou String source = sqscr->get_source_code(); - Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + { + Error err; + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'."); - file->store_string(source); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); - return ERR_CANT_CREATE; + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } } - file->close(); - memdelete(file); if (ScriptServer::is_reload_scripts_on_save_enabled()) { GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index f7fa967883..79171cac73 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -52,6 +52,7 @@ public: _FORCE_INLINE_ const StringName &get_name() const { return name; } Variant _new(); Object *instantiate(); + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; GDScriptNativeClass(const StringName &p_name); }; @@ -265,7 +266,7 @@ class GDScriptInstance : public ScriptInstance { friend struct GDScriptUtilityFunctionsDefinitions; ObjectID owner_id; - Object *owner; + Object *owner = nullptr; Ref<GDScript> script; #ifdef DEBUG_ENABLED Map<StringName, int> member_indices_cache; //used only for hot script reloading @@ -311,17 +312,17 @@ class GDScriptLanguage : public ScriptLanguage { static GDScriptLanguage *singleton; - Variant *_global_array; + Variant *_global_array = nullptr; Vector<Variant> global_array; Map<StringName, int> globals; Map<StringName, Variant> named_globals; struct CallLevel { - Variant *stack; - GDScriptFunction *function; - GDScriptInstance *instance; - int *ip; - int *line; + Variant *stack = nullptr; + GDScriptFunction *function = nullptr; + GDScriptInstance *instance = nullptr; + int *ip = nullptr; + int *line = nullptr; }; int _debug_parse_err_line; @@ -329,7 +330,7 @@ class GDScriptLanguage : public ScriptLanguage { String _debug_error; int _debug_call_stack_pos; int _debug_max_call_stack; - CallLevel *_call_stack; + CallLevel *_call_stack = nullptr; void _add_global(const StringName &p_name, const Variant &p_value); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 00931961b7..01118a6b4f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2508,8 +2508,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a call_type = return_type; } else { - // Check if the name exists as something else. bool found = false; + + // Check if the name exists as something else. if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) { GDScriptParser::IdentifierNode *callee_id; if (callee_type == GDScriptParser::Node::IDENTIFIER) { @@ -2539,6 +2540,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a if (!found && (is_self || (base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN))) { String base_name = is_self && !p_call->is_super ? "self" : base_type.to_string(); push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee); + } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) { + push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type.operator String()), p_call); } } @@ -3773,6 +3776,7 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD r_return_type = type_from_property(p_info.return_val); r_default_arg_count = p_info.default_arguments.size(); r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0; + r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0; for (const PropertyInfo &E : p_info.arguments) { r_par_types.push_back(type_from_property(E)); diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 82aa14795e..000d36d2e6 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -1080,6 +1080,24 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_ append(Variant::get_validated_builtin_method(p_type, p_method)); } +void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) { + bool is_validated = false; + + MethodBind *method = ClassDB::get_method(p_class, p_method); + + if (!is_validated) { + // Perform regular call. + append(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_target); + append(method); + append(p_arguments.size()); + return; + } +} + void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) { append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index db15dc55ef..222ae13390 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -464,6 +464,7 @@ public: virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; + virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 6ada7d36f5..8c198345c2 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -145,7 +145,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP String GDScriptCache::get_source_code(const String &p_path) { Vector<uint8_t> source_file; Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { ERR_FAIL_COND_V(err, ""); } @@ -153,7 +153,6 @@ String GDScriptCache::get_source_code(const String &p_path) { uint64_t len = f->get_length(); source_file.resize(len + 1); uint64_t r = f->get_buffer(source_file.ptrw(), len); - f->close(); ERR_FAIL_COND_V(r != len, ""); source_file.write[len] = 0; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index 4542dd94ae..3d42ce06c0 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -125,6 +125,7 @@ public: virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; + virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 8190eecbc7..0138147fcc 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -35,6 +35,7 @@ #include "gdscript_cache.h" #include "gdscript_utility_functions.h" +#include "core/config/engine.h" #include "core/config/project_settings.h" bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) { @@ -575,6 +576,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // May be static built-in method call. if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); + } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") && + ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) { + // It's a static native method call. + gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); } else { GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); if (r_error) { diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index cc0be94a9e..e5fbbfa0c1 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -564,6 +564,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 5 + argc; } break; + case OPCODE_CALL_NATIVE_STATIC: { + MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]]; + int argc = _code_ptr[ip + 2 + instr_var_args]; + + text += "call native method static "; + text += DADDR(1 + argc); + text += " = "; + text += method->get_instance_class(); + text += "."; + text += method->get_name(); + text += "("; + + for (int i = 0; i < argc; i++) { + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + text += ")"; + + incr += 4 + argc; + } break; case OPCODE_CALL_PTRCALL_NO_RETURN: { text += "call-ptrcall (no return) "; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 5ed4054c57..718df7a0a6 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -485,6 +485,89 @@ struct GDScriptCompletionIdentifier { const GDScriptParser::ExpressionNode *assigned_expression = nullptr; }; +// LOCATION METHODS +// These methods are used to populate the `CodeCompletionOption::location` integer. +// For these methods, the location is based on the depth in the inheritance chain that the property +// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D +// will have a "better" (lower) location "score" than a property that is found on CanvasItem. + +static int _get_property_location(StringName p_class, StringName p_property) { + if (!ClassDB::has_property(p_class, p_property)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_property(class_test, p_property, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_constant_location(StringName p_class, StringName p_constant) { + if (!ClassDB::has_integer_constant(p_class, p_constant)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_integer_constant(class_test, p_constant, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_signal_location(StringName p_class, StringName p_signal) { + if (!ClassDB::has_signal(p_class, p_signal)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_signal(class_test, p_signal, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_method_location(StringName p_class, StringName p_method) { + if (!ClassDB::has_method(p_class, p_method)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::has_method(class_test, p_method, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) { + if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) { + return ScriptLanguage::LOCATION_OTHER; + } + + int depth = 0; + StringName class_test = p_class; + while (class_test && !ClassDB::get_integer_constant_enum(class_test, p_enum_constant, true)) { + class_test = ClassDB::get_parent_class(class_test); + depth++; + } + + return depth | ScriptLanguage::LOCATION_PARENT_MASK; +} + +// END LOCATION METHODS + static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) { if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { String enum_name = p_info.class_name; @@ -694,7 +777,22 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a } } +static void _find_built_in_variants(Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) { + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) { + ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + r_result.insert(option.display, option); + } else { + ScriptLanguage::CodeCompletionOption option(Variant::get_type_name(Variant::Type(i)), ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + r_result.insert(option.display, option); + } + } +} + static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { + // Built-in Variant Types + _find_built_in_variants(r_result, true); + List<StringName> native_types; ClassDB::get_class_list(&native_types); for (const StringName &E : native_types) { @@ -721,18 +819,18 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio const GDScriptParser::ClassNode::Member &member = current->members[i]; switch (member.type) { case GDScriptParser::ClassNode::Member::CLASS: { - ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL); r_result.insert(option.display, option); } break; case GDScriptParser::ClassNode::Member::ENUM: { if (!p_inherit_only) { - ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM); + ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, ScriptLanguage::LOCATION_LOCAL); r_result.insert(option.display, option); } } break; case GDScriptParser::ClassNode::Member::CONSTANT: { if (member.constant->get_datatype().is_meta_type && p_context.current_class->outer != nullptr) { - ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL); r_result.insert(option.display, option); } } break; @@ -748,7 +846,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); for (const StringName &E : global_classes) { - ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE); r_result.insert(option.display, option); } @@ -759,7 +857,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") { continue; } - ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE); r_result.insert(option.display, option); } } @@ -768,10 +866,10 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, for (int i = 0; i < p_suite->locals.size(); i++) { ScriptLanguage::CodeCompletionOption option; if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) { - option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, ScriptLanguage::LOCATION_LOCAL); option.default_value = p_suite->locals[i].constant->initializer->reduced_value; } else { - option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE); + option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE, ScriptLanguage::LOCATION_LOCAL); } r_result.insert(option.display, option); } @@ -788,8 +886,10 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (!p_parent_only) { bool outer = false; const GDScriptParser::ClassNode *clss = p_class; + int classes_processed = 0; while (clss) { for (int i = 0; i < clss->members.size(); i++) { + const int location = (classes_processed + p_recursion_depth) | ScriptLanguage::LOCATION_PARENT_MASK; const GDScriptParser::ClassNode::Member &member = clss->members[i]; ScriptLanguage::CodeCompletionOption option; switch (member.type) { @@ -797,7 +897,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (p_only_functions || outer || (p_static)) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); + option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); break; case GDScriptParser::ClassNode::Member::CONSTANT: if (p_only_functions) { @@ -806,7 +906,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (r_result.has(member.constant->identifier->name)) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); if (member.constant->initializer) { option.default_value = member.constant->initializer->reduced_value; } @@ -815,25 +915,25 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (p_only_functions) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, location); break; case GDScriptParser::ClassNode::Member::ENUM_VALUE: if (p_only_functions) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); break; case GDScriptParser::ClassNode::Member::ENUM: if (p_only_functions) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM); + option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location); break; case GDScriptParser::ClassNode::Member::FUNCTION: if (outer || (p_static && !member.function->is_static) || member.function->identifier->name.operator String().begins_with("@")) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); if (member.function->parameters.size() > 0) { option.insert_text += "("; } else { @@ -844,7 +944,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, if (p_only_functions || outer) { continue; } - option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL); + option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); break; case GDScriptParser::ClassNode::Member::UNDEFINED: break; @@ -853,6 +953,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, } outer = true; clss = clss->outer; + classes_processed++; } } @@ -871,7 +972,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base bool _static = base_type.is_meta_type; if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { - ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL); option.insert_text += "("; r_result.insert(option.display, option); } @@ -891,21 +992,24 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<PropertyInfo> members; scr->get_script_property_list(&members); for (const PropertyInfo &E : members) { - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); + int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.class_name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); } } Map<StringName, Variant> constants; scr->get_constants(&constants); for (const KeyValue<StringName, Variant> &E : constants) { - ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key); + ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); r_result.insert(option.display, option); } List<MethodInfo> signals; scr->get_script_signal_list(&signals); for (const MethodInfo &E : signals) { - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL); + int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); r_result.insert(option.display, option); } } @@ -916,7 +1020,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (E.name.begins_with("@")) { continue; } - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); if (E.arguments.size()) { option.insert_text += "("; } else { @@ -946,7 +1051,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<String> constants; ClassDB::get_integer_constant_list(type, &constants); for (const String &E : constants) { - ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + int location = p_recursion_depth + _get_constant_location(type, StringName(E)); + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); r_result.insert(option.display, option); } @@ -960,29 +1066,33 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (E.name.contains("/")) { continue; } - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); + int location = p_recursion_depth + _get_property_location(type, E.class_name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); } } } - if (!_static || Engine::get_singleton()->has_singleton(type)) { - List<MethodInfo> methods; - ClassDB::get_method_list(type, &methods, false, true); - for (const MethodInfo &E : methods) { - if (E.name.begins_with("_")) { - continue; - } - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); - if (E.arguments.size()) { - option.insert_text += "("; - } else { - option.insert_text += "()"; - } - r_result.insert(option.display, option); + bool only_static = _static && !Engine::get_singleton()->has_singleton(type); + + List<MethodInfo> methods; + ClassDB::get_method_list(type, &methods, false, true); + for (const MethodInfo &E : methods) { + if (only_static && (E.flags & METHOD_FLAG_STATIC) == 0) { + continue; + } + if (E.name.begins_with("_")) { + continue; } + int location = p_recursion_depth + _get_method_location(type, E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); + if (E.arguments.size()) { + option.insert_text += "("; + } else { + option.insert_text += "()"; + } + r_result.insert(option.display, option); } - return; } break; case GDScriptParser::DataType::BUILTIN: { @@ -1058,17 +1168,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool return; } - static const char *_type_names[Variant::VARIANT_MAX] = { - "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D", - "Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray", - "PackedVector2Array", "PackedVector3Array", "PackedColorArray" - }; - static_assert((sizeof(_type_names) / sizeof(*_type_names)) == Variant::VARIANT_MAX, "Completion for builtin types is incomplete"); - - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - ScriptLanguage::CodeCompletionOption option(_type_names[i], ScriptLanguage::CODE_COMPLETION_KIND_CLASS); - r_result.insert(option.display, option); - } + _find_built_in_variants(r_result); static const char *_keywords[] = { "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super", @@ -2242,7 +2342,8 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); for (const StringName &E : enum_constants) { String candidate = class_name + "." + E; - ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM); + int location = _get_enum_constant_location(class_name, E); + ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location); r_result.insert(option.display, option); } } diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 3ee664c76d..a7ad2b65fd 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -259,6 +259,7 @@ public: OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND_RET, OPCODE_CALL_BUILTIN_STATIC, + OPCODE_CALL_NATIVE_STATIC, // ptrcall have one instruction per return type. OPCODE_CALL_PTRCALL_NO_RETURN, OPCODE_CALL_PTRCALL_BOOL, diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 0da1896936..487b7d0449 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -312,7 +312,7 @@ public: bool is_constant = false; Variant reduced_value; - virtual bool is_expression() const { return true; } + virtual bool is_expression() const override { return true; } virtual ~ExpressionNode() {} protected: diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 16b2dac343..89d94d8635 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -432,21 +432,21 @@ struct GDScriptUtilityFunctionsDefinitions { } static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - String str; + String s; for (int i = 0; i < p_arg_count; i++) { - str += p_args[i]->operator String(); + s += p_args[i]->operator String(); } if (Thread::get_caller_id() == Thread::get_main_id()) { ScriptLanguage *script = GDScriptLanguage::get_singleton(); if (script->debug_get_stack_level_count() > 0) { - str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()"; + s += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()"; } } else { - str += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id()); + s += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id()); } - print_line(str); + print_line(s); *r_ret = Variant(); } diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 41c59c7703..152f548f4e 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -93,9 +93,13 @@ static String _get_var_type(const Variant *p_var) { basestr = "null instance"; } } else { - basestr = bobj->get_class(); - if (bobj->get_script_instance()) { - basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; + if (bobj->is_class_ptr(GDScriptNativeClass::get_class_ptr_static())) { + basestr = Object::cast_to<GDScriptNativeClass>(bobj)->get_name(); + } else { + basestr = bobj->get_class(); + if (bobj->get_script_instance()) { + basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; + } } } @@ -263,6 +267,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND_RET, \ &&OPCODE_CALL_BUILTIN_STATIC, \ + &&OPCODE_CALL_NATIVE_STATIC, \ &&OPCODE_CALL_PTRCALL_NO_RETURN, \ &&OPCODE_CALL_PTRCALL_BOOL, \ &&OPCODE_CALL_PTRCALL_INT, \ @@ -1710,6 +1715,47 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_NATIVE_STATIC) { + CHECK_SPACE(3 + instr_arg_count); + + ip += instr_arg_count; + + GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= _methods_count); + MethodBind *method = _methods_ptr[_code_ptr[ip + 1]]; + + int argc = _code_ptr[ip + 2]; + GD_ERR_BREAK(argc < 0); + + GET_INSTRUCTION_ARG(ret, argc); + + const Variant **argptrs = const_cast<const Variant **>(instruction_args); + +#ifdef DEBUG_ENABLED + uint64_t call_time = 0; + + if (GDScriptLanguage::get_singleton()->profiling) { + call_time = OS::get_singleton()->get_ticks_usec(); + } +#endif + + Callable::CallError err; + *ret = method->call(nullptr, argptrs, argc, err); + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { + function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + } + + if (err.error != Callable::CallError::CALL_OK) { + err_text = _get_call_error(err, "static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs); + OPCODE_BREAK; + } +#endif + + ip += 3; + } + DISPATCH_OPCODE; + #ifdef DEBUG_ENABLED #define OPCODE_CALL_PTR(m_type) \ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \ diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 17886181d5..4c4e810370 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -108,7 +108,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) { document_links.clear(); GDScriptTokenizer tokenizer; - FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); + Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); tokenizer.set_source_code(p_code); while (true) { GDScriptTokenizer::Token token = tokenizer.scan(); diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index d5ef8fed74..c42bd58aeb 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -424,10 +424,6 @@ GDScriptTextDocument::GDScriptTextDocument() { file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES); } -GDScriptTextDocument::~GDScriptTextDocument() { - memdelete(file_checker); -} - void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) { String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path); GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index eb7b2c0240..9732765f34 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -40,7 +40,7 @@ class GDScriptTextDocument : public RefCounted { protected: static void _bind_methods(); - FileAccess *file_checker; + Ref<FileAccess> file_checker; void didOpen(const Variant &p_param); void didClose(const Variant &p_param); @@ -75,7 +75,6 @@ public: void initialize(); GDScriptTextDocument(); - virtual ~GDScriptTextDocument(); }; #endif diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 1bf0b40842..229c322f26 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -221,7 +221,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) { Error err; - DirAccessRef dir = DirAccess::open(p_root_dir, &err); + Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err); if (OK == err) { dir->list_dir_begin(); String file_name = dir->get_next(); diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index e8ddf90836..e78517a708 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -80,7 +80,7 @@ void init_autoloads() { } else if (script.is_valid()) { StringName ibt = script->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); + ERR_CONTINUE_MSG(!valid_type, "Script does not inherit from Node: " + info.path); Object *obj = ClassDB::instantiate(ibt); @@ -229,7 +229,7 @@ bool GDScriptTestRunner::generate_outputs() { bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { Error err = OK; - DirAccessRef dir(DirAccess::open(p_dir, &err)); + Ref<DirAccess> dir(DirAccess::open(p_dir, &err)); if (err != OK) { return false; @@ -254,7 +254,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { #ifndef DEBUG_ENABLED // On release builds, skip tests marked as debug only. Error open_err = OK; - FileAccessRef script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err)); + Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err)); if (open_err != OK) { ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next)); next = dir->get_next(); @@ -286,7 +286,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { bool GDScriptTestRunner::make_tests() { Error err = OK; - DirAccessRef dir(DirAccess::open(source_dir, &err)); + Ref<DirAccess> dir(DirAccess::open(source_dir, &err)); ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory."); @@ -611,7 +611,7 @@ bool GDScriptTest::generate_output() { } Error err = OK; - FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); + Ref<FileAccess> out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); if (err != OK) { return false; } @@ -620,7 +620,6 @@ bool GDScriptTest::generate_output() { output += "\n"; // Make sure to insert newline for CI static checks. out_file->store_string(output); - out_file->close(); return true; } diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h index 1a950c6898..d6c6419e21 100644 --- a/modules/gdscript/tests/gdscript_test_runner.h +++ b/modules/gdscript/tests/gdscript_test_runner.h @@ -63,8 +63,8 @@ public: private: struct ErrorHandlerData { - TestResult *result; - GDScriptTest *self; + TestResult *result = nullptr; + GDScriptTest *self = nullptr; ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) { result = p_result; self = p_this; diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 4255030b4e..d8f60d5e9b 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -204,8 +204,8 @@ void test(TestType p_type) { return; } - FileAccessRef fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test); + Ref<FileAccess> fa = FileAccess::open(test, FileAccess::READ); + ERR_FAIL_COND_MSG(fa.is_null(), "Could not open file: " + test); // Initialize the language for the test routine. init_language(fa->get_path_absolute().get_base_dir()); diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index cdb22b7d19..ae05c1b68d 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -62,10 +62,11 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. - const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path); + // Escape paths to be valid Python strings to embed in the script. + const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape(); const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file( vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text())); - const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink); + const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape(); // Handle configuration options. diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index 05e8a565f7..9a1b5f5803 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -84,11 +84,11 @@ class Label; class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImportFormatSupportQuery { GDCLASS(EditorFileSystemImportFormatSupportQueryBlend, EditorFileSystemImportFormatSupportQuery); - ConfirmationDialog *configure_blender_dialog; - LineEdit *blender_path; - Button *blender_path_browse; - EditorFileDialog *browse_dialog; - Label *path_status; + ConfirmationDialog *configure_blender_dialog = nullptr; + LineEdit *blender_path = nullptr; + Button *blender_path_browse = nullptr; + EditorFileDialog *browse_dialog = nullptr; + Label *path_status = nullptr; bool confirmed = false; String auto_detected_path; diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index 7cfd85c73a..24564f55be 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -53,10 +53,13 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. - const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path); + // Don't use `c_escape()` as it can generate broken paths. These paths will be + // enclosed in double quotes by OS::execute(), so we only need to escape those. + // `c_escape_multiline()` seems to do this (escapes `\` and `"` only). + const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline(); const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file( vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text())); - const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink); + const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline(); // Run fbx2gltf. @@ -65,9 +68,9 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t List<String> args; args.push_back("--pbr-metallic-roughness"); args.push_back("--input"); - args.push_back(vformat("\"%s\"", source_global)); + args.push_back(source_global); args.push_back("--output"); - args.push_back(vformat("\"%s\"", sink_global)); + args.push_back(sink_global); args.push_back("--binary"); String standard_out; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index ee756c6d2e..73222330db 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -256,8 +256,8 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) { Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { return err; } @@ -278,7 +278,7 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { return OK; } -Error GLTFDocument::_parse_glb(FileAccess *f, Ref<GLTFState> state) { +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); @@ -696,8 +696,8 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); + if (f.is_null()) { return err; } if (buffer_data.size() == 0) { @@ -705,7 +705,6 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat } f->create(FileAccess::ACCESS_RESOURCES); f->store_buffer(buffer_data.ptr(), buffer_data.size()); - f->close(); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); @@ -729,8 +728,8 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); + if (f.is_null()) { return err; } if (buffer_data.size() == 0) { @@ -738,7 +737,6 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa } f->create(FileAccess::ACCESS_RESOURCES); f->store_buffer(buffer_data.ptr(), buffer_data.size()); - f->close(); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); @@ -3021,7 +3019,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path String texture_dir = "textures"; String path = p_path.get_base_dir(); String new_texture_dir = path + "/" + texture_dir; - DirAccessRef da = DirAccess::open(path); + Ref<DirAccess> da = DirAccess::open(path); if (!da->dir_exists(new_texture_dir)) { da->make_dir(new_texture_dir); } @@ -6097,7 +6095,14 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, animation->set_length(length); - ap->add_animation(name, animation); + Ref<AnimationLibrary> library; + if (!ap->has_animation_library("")) { + library.instantiate(); + ap->add_animation_library("", library); + } else { + library = ap->get_animation_library(""); + } + library->add_animation(name, animation); } void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { @@ -6588,9 +6593,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } -Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps) { +Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) { Error err; - if (!f) { + if (f.is_null()) { return FAILED; } f->seek(0); @@ -6614,7 +6619,6 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, i ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); state->json = json.get_data(); } - f->close(); if (!state->json.has("asset")) { return ERR_PARSE_ERROR; @@ -6703,8 +6707,8 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { if (p_path.to_lower().ends_with("glb")) { err = _encode_buffer_glb(state, p_path); ERR_FAIL_COND_V(err != OK, err); - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(!f, FAILED); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(f.is_null(), FAILED); String json = Variant(state->json).to_json_string(); @@ -6741,18 +6745,15 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { f->store_8(0); } - - f->close(); } else { err = _encode_buffer_bins(state, p_path); ERR_FAIL_COND_V(err != OK, err); - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(!f, FAILED); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(f.is_null(), FAILED); f->create(FileAccess::ACCESS_RESOURCES); String json = Variant(state->json).to_json_string(); f->store_string(json); - f->close(); } return err; } @@ -6927,9 +6928,10 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa ERR_FAIL_COND_V(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; - FileAccessMemory *file_access = memnew(FileAccessMemory); + state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + + Ref<FileAccessMemory> file_access; + file_access.instantiate(); file_access->open_custom(p_bytes.ptr(), p_bytes.size()); err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps); ERR_FAIL_COND_V(err != OK, FAILED); @@ -7032,7 +7034,7 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint r_state->filename = p_path.get_file().get_basename(); r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = 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); String base_path = p_base_path; diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 0b7664a616..19bc507a8d 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -196,7 +196,7 @@ private: Ref<Texture2D> _get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture); Error _parse_json(const String &p_path, Ref<GLTFState> state); - Error _parse_glb(FileAccess *f, 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); @@ -457,7 +457,7 @@ public: void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name); Error _serialize(Ref<GLTFState> state, const String &p_path); - Error _parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps); + Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps); }; #endif // GLTF_DOCUMENT_H diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 4166f92502..e09c76f052 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -87,7 +87,7 @@ static void _editor_init() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE)); if (fbx_enabled) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (fbx2gltf_path.is_empty()) { WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported."); } else if (!da->file_exists(fbx2gltf_path)) { diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index adb0da6e2c..3b29397502 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -62,21 +62,21 @@ class GridMapEditor : public VBoxContainer { DISPLAY_LIST }; - UndoRedo *undo_redo; + UndoRedo *undo_redo = nullptr; InputAction input_action = INPUT_NONE; - Panel *panel; - MenuButton *options; - SpinBox *floor; + Panel *panel = nullptr; + MenuButton *options = nullptr; + SpinBox *floor = nullptr; double accumulated_floor_delta = 0.0; - Button *mode_thumbnail; - Button *mode_list; - LineEdit *search_box; - HSlider *size_slider; - HBoxContainer *spatial_editor_hb; - ConfirmationDialog *settings_dialog; - VBoxContainer *settings_vbc; - SpinBox *settings_pick_distance; - Label *spin_box_label; + Button *mode_thumbnail = nullptr; + Button *mode_list = nullptr; + LineEdit *search_box = nullptr; + HSlider *size_slider = nullptr; + HBoxContainer *spatial_editor_hb = nullptr; + ConfirmationDialog *settings_dialog = nullptr; + VBoxContainer *settings_vbc = nullptr; + SpinBox *settings_pick_distance = nullptr; + Label *spin_box_label = nullptr; struct SetItem { Vector3i position; @@ -89,7 +89,7 @@ class GridMapEditor : public VBoxContainer { List<SetItem> set_items; GridMap *node = nullptr; - MeshLibrary *last_mesh_library; + MeshLibrary *last_mesh_library = nullptr; Transform3D grid_xform; Transform3D edit_grid_xform; @@ -173,15 +173,15 @@ class GridMapEditor : public VBoxContainer { }; - Node3DEditorPlugin *spatial_editor; + Node3DEditorPlugin *spatial_editor = nullptr; struct AreaDisplay { RID mesh; RID instance; }; - ItemList *mesh_library_palette; - Label *info_message; + ItemList *mesh_library_palette = nullptr; + Label *info_message = nullptr; void update_grid(); // Change which and where the grid is displayed void _draw_grids(const Vector3 &cell_size); @@ -234,7 +234,7 @@ public: class GridMapEditorPlugin : public EditorPlugin { GDCLASS(GridMapEditorPlugin, EditorPlugin); - GridMapEditor *grid_map_editor; + GridMapEditor *grid_map_editor = nullptr; protected: void _notification(int p_what); diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index 996bbfadd1..4588caf0a5 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { String header = f->get_token(); ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + "."); diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h index 0213fdbcb2..f2d53cc206 100644 --- a/modules/hdr/image_loader_hdr.h +++ b/modules/hdr/image_loader_hdr.h @@ -35,7 +35,7 @@ class ImageLoaderHDR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderHDR(); }; diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index e8c66ab9da..51358876a4 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -103,7 +103,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p return OK; } -Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -113,8 +113,6 @@ Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force f->get_buffer(&w[0], src_image_len); - f->close(); - Error err = jpeg_load_image_from_buffer(p_image.ptr(), w, src_image_len); return err; diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h index 8e64f6fba7..de9700faec 100644 --- a/modules/jpg/image_loader_jpegd.h +++ b/modules/jpg/image_loader_jpegd.h @@ -35,7 +35,7 @@ class ImageLoaderJPG : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderJPG(); }; diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index ea6b6d8233..e62581ab40 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -55,14 +55,13 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use"); PackedByteArray out; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator - memdelete(f); int ret = 0; if (p_public_only) { @@ -79,8 +78,8 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { } Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); unsigned char w[16000]; memset(w, 0, sizeof(w)); @@ -92,14 +91,12 @@ Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w)); } if (ret != 0) { - memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written. ERR_FAIL_V_MSG(FAILED, "Error writing key '" + itos(ret) + "'."); } size_t len = strlen((char *)w); f->store_buffer(w, len); - memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize temporary buffer. return OK; } @@ -143,14 +140,13 @@ Error X509CertificateMbedTLS::load(String p_path) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is in use"); PackedByteArray out; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator - memdelete(f); int ret = mbedtls_x509_crt_parse(&cert, out.ptr(), out.size()); ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing some certificates: " + itos(ret)); @@ -167,8 +163,8 @@ Error X509CertificateMbedTLS::load_from_memory(const uint8_t *p_buffer, int p_le } Error X509CertificateMbedTLS::save(String p_path) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'."); mbedtls_x509_crt *crt = &cert; while (crt) { @@ -176,14 +172,12 @@ Error X509CertificateMbedTLS::save(String p_path) { size_t wrote = 0; int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote); if (ret != 0 || wrote == 0) { - memdelete(f); ERR_FAIL_V_MSG(FAILED, "Error writing certificate '" + itos(ret) + "'."); } f->store_buffer(w, wrote - 1); // don't write the string terminator crt = crt->next; } - memdelete(f); return OK; } diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp index 2a5eaa0109..ddc2e945a7 100644 --- a/modules/mbedtls/packet_peer_mbed_dtls.cpp +++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp @@ -35,11 +35,11 @@ #include "core/io/stream_peer_ssl.h" int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx; + PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); @@ -53,11 +53,11 @@ int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len } int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx; + PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp index 05a57607cd..1818048877 100644 --- a/modules/mbedtls/stream_peer_mbedtls.cpp +++ b/modules/mbedtls/stream_peer_mbedtls.cpp @@ -34,11 +34,11 @@ #include "core/io/stream_peer_tcp.h" int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx; + StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); @@ -54,11 +54,11 @@ int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) } int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) { - if (buf == nullptr || len <= 0) { + if (buf == nullptr || len == 0) { return 0; } - StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx; + StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx); ERR_FAIL_COND_V(sp == nullptr, 0); diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index 0e0da806bf..6cd710e792 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -75,9 +75,8 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_OPEN); uint64_t len = f->get_length(); @@ -87,8 +86,6 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s f->get_buffer(w, len); - memdelete(f); - Ref<AudioStreamMP3> mp3_stream; mp3_stream.instantiate(); diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 5884a24454..9253f105bb 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -238,11 +238,10 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { } } - FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'."); JSON json; f->store_string(json.stringify(classes_dict, "\t")); - f->close(); print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 8acd119880..02aebb3805 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -3641,20 +3641,18 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r } #endif - Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'."); + { + Error err; + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'."); - file->store_string(source); + file->store_string(source); - if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); - return ERR_CANT_CREATE; + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } } - file->close(); - memdelete(file); - #ifdef TOOLS_ENABLED if (ScriptServer::is_reload_scripts_on_save_enabled()) { CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index d8f5b814e4..2a93c15282 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1035,8 +1035,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(p_proj_dir)) { Error err = da->make_dir_recursive(p_proj_dir); @@ -1170,8 +1170,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(p_proj_dir)) { Error err = da->make_dir_recursive(p_proj_dir); @@ -1280,8 +1280,8 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) { String output_dir = path::abspath(path::realpath(p_output_dir)); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(output_dir)) { Error err = da->make_dir_recursive(output_dir); @@ -2255,12 +2255,10 @@ uint32_t BindingsGenerator::get_version() { } Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE); - - ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'."); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'."); file->store_string(p_content.as_string()); - file->close(); return OK; } diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index 3a41b3f6f5..79015686c3 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -144,7 +144,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr } } break; case CompletionKind::SCENE_PATHS: { - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); List<String> directories; directories.push_back(dir_access->get_current_dir()); diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h index 7c991d87a4..4405809887 100644 --- a/modules/mono/glue/arguments_vector.h +++ b/modules/mono/glue/arguments_vector.h @@ -37,7 +37,7 @@ template <typename T, int POOL_SIZE = 5> struct ArgumentsVector { private: T pool[POOL_SIZE]; - T *_ptr; + T *_ptr = nullptr; int size; ArgumentsVector() = delete; diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 7c2cb2e260..cb2b60fcce 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -76,7 +76,7 @@ String _get_mono_user_dir() { exe_dir = exe_dir.plus_file("../../..").simplify_path(); } - DirAccessRef d = DirAccess::create_for_path(exe_dir); + Ref<DirAccess> d = DirAccess::create_for_path(exe_dir); if (d->file_exists("._sc_") || d->file_exists("_sc_")) { // contain yourself diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h index ea7231f43b..d50a8a7b08 100644 --- a/modules/mono/managed_callable.h +++ b/modules/mono/managed_callable.h @@ -43,7 +43,7 @@ class ManagedCallable : public CallableCustom { friend class CSharpLanguage; MonoGCHandleData delegate_handle; - GDMonoMethod *delegate_invoke; + GDMonoMethod *delegate_invoke = nullptr; #ifdef GD_MONO_HOT_RELOAD SelfList<ManagedCallable> self_instance = this; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 424b74906f..e98ce8f6c1 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -643,7 +643,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const // Create destination directory if needed if (!DirAccess::exists(dst_dir)) { - DirAccessRef da = DirAccess::create_for_path(dst_dir); + Ref<DirAccess> da = DirAccess::create_for_path(dst_dir); Error err = da->make_dir_recursive(dst_dir); if (err != OK) { @@ -652,7 +652,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const } } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String xml_file = assembly_name + ".xml"; if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) { diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index aab0b31c37..51fd0f8483 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -94,16 +94,16 @@ private: UnhandledExceptionPolicy unhandled_exception_policy; - MonoDomain *root_domain; - MonoDomain *scripts_domain; + MonoDomain *root_domain = nullptr; + MonoDomain *scripts_domain = nullptr; HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies; - GDMonoAssembly *corlib_assembly; - GDMonoAssembly *project_assembly; + GDMonoAssembly *corlib_assembly = nullptr; + GDMonoAssembly *project_assembly = nullptr; #ifdef TOOLS_ENABLED - GDMonoAssembly *tools_assembly; - GDMonoAssembly *tools_project_editor_assembly; + GDMonoAssembly *tools_assembly = nullptr; + GDMonoAssembly *tools_project_editor_assembly = nullptr; #endif LoadedApiAssembly core_api_assembly; @@ -150,7 +150,7 @@ private: void _init_godot_api_hashes(); void _init_exception_policy(); - GDMonoLog *gdmono_log; + GDMonoLog *gdmono_log = nullptr; #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) MonoRegInfo mono_reg_info; @@ -250,7 +250,7 @@ public: namespace gdmono { class ScopeDomain { - MonoDomain *prev_domain; + MonoDomain *prev_domain = nullptr; public: ScopeDomain(MonoDomain *p_domain) { @@ -270,7 +270,7 @@ public: }; class ScopeExitDomainUnload { - MonoDomain *domain; + MonoDomain *domain = nullptr; public: ScopeExitDomainUnload(MonoDomain *p_domain) : diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index b25d773be7..a96357b082 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -68,8 +68,8 @@ class GDMonoAssembly { }; String name; - MonoImage *image; - MonoAssembly *assembly; + MonoImage *image = nullptr; + MonoAssembly *assembly = nullptr; bool attrs_fetched = false; MonoCustomAttrInfo *attributes = nullptr; diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 49f47b0a15..4000342c94 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -41,91 +41,91 @@ struct CachedData { // corlib classes // Let's use the no-namespace format for these too - GDMonoClass *class_MonoObject; // object - GDMonoClass *class_bool; // bool - GDMonoClass *class_int8_t; // sbyte - GDMonoClass *class_int16_t; // short - GDMonoClass *class_int32_t; // int - GDMonoClass *class_int64_t; // long - GDMonoClass *class_uint8_t; // byte - GDMonoClass *class_uint16_t; // ushort - GDMonoClass *class_uint32_t; // uint - GDMonoClass *class_uint64_t; // ulong - GDMonoClass *class_float; // float - GDMonoClass *class_double; // double - GDMonoClass *class_String; // string - GDMonoClass *class_IntPtr; // System.IntPtr - - GDMonoClass *class_System_Collections_IEnumerable; - GDMonoClass *class_System_Collections_ICollection; - GDMonoClass *class_System_Collections_IDictionary; + GDMonoClass *class_MonoObject = nullptr; // object + GDMonoClass *class_bool = nullptr; // bool + GDMonoClass *class_int8_t = nullptr; // sbyte + GDMonoClass *class_int16_t = nullptr; // short + GDMonoClass *class_int32_t = nullptr; // int + GDMonoClass *class_int64_t = nullptr; // long + GDMonoClass *class_uint8_t = nullptr; // byte + GDMonoClass *class_uint16_t = nullptr; // ushort + GDMonoClass *class_uint32_t = nullptr; // uint + GDMonoClass *class_uint64_t = nullptr; // ulong + GDMonoClass *class_float = nullptr; // float + GDMonoClass *class_double = nullptr; // double + GDMonoClass *class_String = nullptr; // string + GDMonoClass *class_IntPtr = nullptr; // System.IntPtr + + GDMonoClass *class_System_Collections_IEnumerable = nullptr; + GDMonoClass *class_System_Collections_ICollection = nullptr; + GDMonoClass *class_System_Collections_IDictionary = nullptr; #ifdef DEBUG_ENABLED - GDMonoClass *class_System_Diagnostics_StackTrace; + GDMonoClass *class_System_Diagnostics_StackTrace = nullptr; GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr; #endif - GDMonoClass *class_KeyNotFoundException; + GDMonoClass *class_KeyNotFoundException = nullptr; - MonoClass *rawclass_Dictionary; + MonoClass *rawclass_Dictionary = nullptr; // ----------------------------------------------- - GDMonoClass *class_Vector2; - GDMonoClass *class_Vector2i; - GDMonoClass *class_Rect2; - GDMonoClass *class_Rect2i; - GDMonoClass *class_Transform2D; - GDMonoClass *class_Vector3; - GDMonoClass *class_Vector3i; - GDMonoClass *class_Basis; - GDMonoClass *class_Quaternion; - GDMonoClass *class_Transform3D; - GDMonoClass *class_AABB; - GDMonoClass *class_Color; - GDMonoClass *class_Plane; - GDMonoClass *class_StringName; - GDMonoClass *class_NodePath; - GDMonoClass *class_RID; - GDMonoClass *class_GodotObject; - GDMonoClass *class_GodotResource; - GDMonoClass *class_Node; - GDMonoClass *class_Control; - GDMonoClass *class_Node3D; - GDMonoClass *class_WeakRef; - GDMonoClass *class_Callable; - GDMonoClass *class_SignalInfo; - GDMonoClass *class_Array; - GDMonoClass *class_Dictionary; - GDMonoClass *class_MarshalUtils; - GDMonoClass *class_ISerializationListener; + GDMonoClass *class_Vector2 = nullptr; + GDMonoClass *class_Vector2i = nullptr; + GDMonoClass *class_Rect2 = nullptr; + GDMonoClass *class_Rect2i = nullptr; + GDMonoClass *class_Transform2D = nullptr; + GDMonoClass *class_Vector3 = nullptr; + GDMonoClass *class_Vector3i = nullptr; + GDMonoClass *class_Basis = nullptr; + GDMonoClass *class_Quaternion = nullptr; + GDMonoClass *class_Transform3D = nullptr; + GDMonoClass *class_AABB = nullptr; + GDMonoClass *class_Color = nullptr; + GDMonoClass *class_Plane = nullptr; + GDMonoClass *class_StringName = nullptr; + GDMonoClass *class_NodePath = nullptr; + GDMonoClass *class_RID = nullptr; + GDMonoClass *class_GodotObject = nullptr; + GDMonoClass *class_GodotResource = nullptr; + GDMonoClass *class_Node = nullptr; + GDMonoClass *class_Control = nullptr; + GDMonoClass *class_Node3D = nullptr; + GDMonoClass *class_WeakRef = nullptr; + GDMonoClass *class_Callable = nullptr; + GDMonoClass *class_SignalInfo = nullptr; + GDMonoClass *class_Array = nullptr; + GDMonoClass *class_Dictionary = nullptr; + GDMonoClass *class_MarshalUtils = nullptr; + GDMonoClass *class_ISerializationListener = nullptr; #ifdef DEBUG_ENABLED - GDMonoClass *class_DebuggingUtils; + GDMonoClass *class_DebuggingUtils = nullptr; GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo; #endif - GDMonoClass *class_ExportAttribute; - GDMonoField *field_ExportAttribute_hint; - GDMonoField *field_ExportAttribute_hintString; - GDMonoClass *class_SignalAttribute; - GDMonoClass *class_ToolAttribute; - GDMonoClass *class_AnyPeerAttribute; - GDMonoClass *class_AuthorityAttribute; - GDMonoClass *class_GodotMethodAttribute; - GDMonoField *field_GodotMethodAttribute_methodName; - GDMonoClass *class_ScriptPathAttribute; - GDMonoField *field_ScriptPathAttribute_path; - GDMonoClass *class_AssemblyHasScriptsAttribute; - GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup; - GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes; - - GDMonoField *field_GodotObject_ptr; - GDMonoField *field_StringName_ptr; - GDMonoField *field_NodePath_ptr; - GDMonoField *field_Image_ptr; - GDMonoField *field_RID_ptr; + GDMonoClass *class_ExportAttribute = nullptr; + GDMonoField *field_ExportAttribute_hint = nullptr; + GDMonoField *field_ExportAttribute_hintString = nullptr; + GDMonoClass *class_SignalAttribute = nullptr; + GDMonoClass *class_ToolAttribute = nullptr; + GDMonoClass *class_AnyPeerAttribute = nullptr; + GDMonoClass *class_AuthorityAttribute = nullptr; + GDMonoClass *class_GodotMethodAttribute = nullptr; + GDMonoField *field_GodotMethodAttribute_methodName = nullptr; + GDMonoClass *class_ScriptPathAttribute = nullptr; + GDMonoField *field_ScriptPathAttribute_path = nullptr; + GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr; + GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr; + GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr; + + GDMonoField *field_GodotObject_ptr = nullptr; + GDMonoField *field_StringName_ptr = nullptr; + GDMonoField *field_NodePath_ptr = nullptr; + GDMonoField *field_Image_ptr = nullptr; + GDMonoField *field_RID_ptr = nullptr; GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose; GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr; diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index bfb5797d4b..b32d561f61 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -70,11 +70,11 @@ class GDMonoClass { StringName namespace_name; StringName class_name; - MonoClass *mono_class; - GDMonoAssembly *assembly; + MonoClass *mono_class = nullptr; + GDMonoAssembly *assembly = nullptr; bool attrs_fetched; - MonoCustomAttrInfo *attributes; + MonoCustomAttrInfo *attributes = nullptr; // This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions. // Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming. diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h index abcdef378c..87ef245f3f 100644 --- a/modules/mono/mono_gd/gd_mono_field.h +++ b/modules/mono/mono_gd/gd_mono_field.h @@ -36,14 +36,14 @@ #include "i_mono_class_member.h" class GDMonoField : public IMonoClassMember { - GDMonoClass *owner; - MonoClassField *mono_field; + GDMonoClass *owner = nullptr; + MonoClassField *mono_field = nullptr; StringName name; ManagedType type; bool attrs_fetched; - MonoCustomAttrInfo *attributes; + MonoCustomAttrInfo *attributes = nullptr; public: virtual GDMonoClass *get_enclosing_class() const final { return owner; } diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index 01a6521876..6ea3c5539e 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -77,23 +77,20 @@ static String make_text(const char *log_domain, const char *log_level, const cha } void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) { - FileAccess *f = GDMonoLog::get_singleton()->log_file; - if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) { String text = make_text(log_domain, log_level, message); text += "\n"; - f->seek_end(); - f->store_string(text); + GDMonoLog::get_singleton()->log_file->seek_end(); + GDMonoLog::get_singleton()->log_file->store_string(text); } if (fatal) { String text = make_text(log_domain, log_level, message); ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'."); // Make sure to flush before aborting - f->flush(); - f->close(); - memdelete(f); + GDMonoLog::get_singleton()->log_file->flush(); + GDMonoLog::get_singleton()->log_file.unref(); abort(); } @@ -101,8 +98,8 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { if (!DirAccess::exists(p_logs_dir)) { - DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!diraccess, false); + Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(diraccess.is_null(), false); Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir); ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory."); } @@ -113,8 +110,8 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { static const uint64_t MAX_SECS = 5 * 86400; // 5 days - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND(!da); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND(da.is_null()); Error err = da->change_dir(p_logs_dir); ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'."); @@ -170,7 +167,7 @@ void GDMonoLog::initialize() { log_file_path = logs_dir.plus_file(log_file_name); log_file = FileAccess::open(log_file_path, FileAccess::WRITE); - if (!log_file) { + if (log_file.is_null()) { ERR_PRINT("Mono: Cannot create log file at: " + log_file_path); } } @@ -178,7 +175,7 @@ void GDMonoLog::initialize() { mono_trace_set_level_string(log_level.get_data()); log_level_id = get_log_level_id(log_level.get_data()); - if (log_file) { + if (log_file.is_valid()) { OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data()); mono_trace_set_log_handler(mono_log_callback, this); } else { @@ -192,11 +189,6 @@ GDMonoLog::GDMonoLog() { GDMonoLog::~GDMonoLog() { singleton = nullptr; - - if (log_file) { - log_file->close(); - memdelete(log_file); - } } #else diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index 9aa67a09e2..9fc35f8e31 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -48,7 +48,7 @@ class GDMonoLog { #ifdef GD_MONO_LOG_ENABLED int log_level_id = -1; - FileAccess *log_file = nullptr; + Ref<FileAccess> log_file; String log_file_path; bool _try_create_logs_dir(const String &p_logs_dir); diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 20d4743e5c..eb33c6119e 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -196,14 +196,14 @@ PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array); #pragma pack(push, 1) struct M_Callable { - MonoObject *target; - MonoObject *method_string_name; - MonoDelegate *delegate; + MonoObject *target = nullptr; + MonoObject *method_string_name = nullptr; + MonoDelegate *delegate = nullptr; }; struct M_SignalInfo { - MonoObject *owner; - MonoObject *name_string_name; + MonoObject *owner = nullptr; + MonoObject *name_string_name = nullptr; }; #pragma pack(pop) diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index 6e87a60ee2..be11ef5bfe 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -54,7 +54,7 @@ class GDMonoMethod : public IMonoClassMember { friend class GDMonoClass; - MonoMethod *mono_method; + MonoMethod *mono_method = nullptr; public: virtual GDMonoClass *get_enclosing_class() const final; diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index 003bcf05e1..6fc681aeb5 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -36,14 +36,14 @@ #include "i_mono_class_member.h" class GDMonoProperty : public IMonoClassMember { - GDMonoClass *owner; - MonoProperty *mono_property; + GDMonoClass *owner = nullptr; + MonoProperty *mono_property = nullptr; StringName name; ManagedType type; bool attrs_fetched; - MonoCustomAttrInfo *attributes; + MonoCustomAttrInfo *attributes = nullptr; unsigned int param_buffer_size; diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h index 68299aa984..83e2750e5a 100644 --- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h +++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h @@ -47,11 +47,11 @@ struct Mono_InterpMethodArguments { size_t ilen; void **iargs; size_t flen; - double *fargs; + double *fargs = nullptr; void **retval; size_t is_float_ret; //#ifdef TARGET_WASM - void *sig; + void *sig = nullptr; //#endif }; } // extern "C" diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h index 1a62f36625..532aa3e327 100644 --- a/modules/mono/signal_awaiter_utils.h +++ b/modules/mono/signal_awaiter_utils.h @@ -68,7 +68,7 @@ public: }; class EventSignalCallable : public CallableCustom { - Object *owner; + Object *owner = nullptr; const CSharpScript::EventSignal *event_signal; public: diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index dd29299330..e6975611d2 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -167,15 +167,13 @@ String escape_csharp_keyword(const String &p_name) { Error read_all_file_utf8(const String &p_path, String &r_content) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.h b/modules/navigation/editor/navigation_mesh_editor_plugin.h index 3c3e804fd2..bc9e4185b7 100644 --- a/modules/navigation/editor/navigation_mesh_editor_plugin.h +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.h @@ -42,14 +42,14 @@ class NavigationMeshEditor : public Control { GDCLASS(NavigationMeshEditor, Control); - AcceptDialog *err_dialog; + AcceptDialog *err_dialog = nullptr; - HBoxContainer *bake_hbox; - Button *button_bake; - Button *button_reset; - Label *bake_info; + HBoxContainer *bake_hbox = nullptr; + Button *button_bake = nullptr; + Button *button_reset = nullptr; + Label *bake_info = nullptr; - NavigationRegion3D *node; + NavigationRegion3D *node = nullptr; void _bake_pressed(); void _clear_pressed(); @@ -68,7 +68,7 @@ public: class NavigationMeshEditorPlugin : public EditorPlugin { GDCLASS(NavigationMeshEditorPlugin, EditorPlugin); - NavigationMeshEditor *navigation_mesh_editor; + NavigationMeshEditor *navigation_mesh_editor = nullptr; public: virtual String get_name() const override { return "NavigationMesh"; } diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index f3da85063a..ca4fc4f628 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -109,9 +109,7 @@ } \ void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) -GodotNavigationServer::GodotNavigationServer() : - NavigationServer3D() { -} +GodotNavigationServer::GodotNavigationServer() {} GodotNavigationServer::~GodotNavigationServer() { flush_queries(); diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index c555a358db..7ad5e2d501 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -45,16 +45,16 @@ #define MERGE_INTERNAL(A, B) A##B #define MERGE(A, B) MERGE_INTERNAL(A, B) -#define COMMAND_1(F_NAME, T_0, D_0) \ - virtual void F_NAME(T_0 D_0) const; \ +#define COMMAND_1(F_NAME, T_0, D_0) \ + virtual void F_NAME(T_0 D_0) const override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0) -#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ - virtual void F_NAME(T_0 D_0, T_1 D_1) const; \ +#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ + virtual void F_NAME(T_0 D_0, T_1 D_1) const override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) -#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \ - virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const; \ +#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \ + virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const override; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) class GodotNavigationServer; @@ -85,38 +85,38 @@ public: void add_command(SetCommand *command) const; - virtual RID map_create() const; + virtual RID map_create() const override; COMMAND_2(map_set_active, RID, p_map, bool, p_active); - virtual bool map_is_active(RID p_map) const; + virtual bool map_is_active(RID p_map) const override; COMMAND_2(map_set_up, RID, p_map, Vector3, p_up); - virtual Vector3 map_get_up(RID p_map) const; + virtual Vector3 map_get_up(RID p_map) const override; COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size); - virtual real_t map_get_cell_size(RID p_map) const; + virtual real_t map_get_cell_size(RID p_map) const override; COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin); - virtual real_t map_get_edge_connection_margin(RID p_map) const; + virtual real_t map_get_edge_connection_margin(RID p_map) const override; - virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const; + virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const override; - virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const; - virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const; - virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const; - virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const; + virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override; + virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const override; + virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override; + virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override; - virtual RID region_create() const; + virtual RID region_create() const override; COMMAND_2(region_set_map, RID, p_region, RID, p_map); COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers); - virtual uint32_t region_get_layers(RID p_region) const; + virtual uint32_t region_get_layers(RID p_region) const override; COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh); - virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const; - virtual int region_get_connections_count(RID p_region) const; - virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const; - virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const; + virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override; + virtual int region_get_connections_count(RID p_region) const override; + virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; + virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; - virtual RID agent_create() const; + virtual RID agent_create() const override; COMMAND_2(agent_set_map, RID, p_agent, RID, p_map); COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist); COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count); @@ -127,15 +127,15 @@ public: COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity); 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; + 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_1(free, RID, p_object); - virtual void set_active(bool p_active) const; + virtual void set_active(bool p_active) const override; void flush_queries(); - virtual void process(real_t p_delta_time); + virtual void process(real_t p_delta_time) override; }; #undef COMMAND_1 diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 1151df6390..70d50999f9 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -351,11 +351,15 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p // Add mid points int np_id = least_cost_id; - while (np_id != -1) { - path.push_back(navigation_polys[np_id].entry); + while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) { + int prev = navigation_polys[np_id].back_navigation_edge; + int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size(); + Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5; + path.push_back(point); np_id = navigation_polys[np_id].back_navigation_poly_id; } + path.push_back(begin_point); path.reverse(); } diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index 0c02885b10..5b6c695ca4 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -89,7 +89,7 @@ struct Edge { }; struct Polygon { - NavRegion *owner; + NavRegion *owner = nullptr; /// The points of this `Polygon` std::vector<Point> points; diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 61c3cefc7a..9e2daf3a99 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -124,6 +124,28 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform } } +void NavigationMeshGenerator::_add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) { + Vector<Vector3> mesh_vertices = p_array[Mesh::ARRAY_VERTEX]; + const Vector3 *vr = mesh_vertices.ptr(); + + Vector<int> mesh_indices = p_array[Mesh::ARRAY_INDEX]; + const int *ir = mesh_indices.ptr(); + + const int face_count = mesh_indices.size() / 3; + const int current_vertex_count = p_vertices.size() / 3; + + for (int j = 0; j < mesh_vertices.size(); j++) { + _add_vertex(p_xform.xform(vr[j]), p_vertices); + } + + for (int j = 0; j < face_count; j++) { + // CCW + p_indices.push_back(current_vertex_count + (ir[j * 3 + 0])); + p_indices.push_back(current_vertex_count + (ir[j * 3 + 2])); + p_indices.push_back(current_vertex_count + (ir[j * 3 + 1])); + } +} + void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) { int face_count = p_faces.size() / 3; int current_vertex_count = p_vertices.size() / 3; @@ -187,43 +209,38 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * col_shape->get_transform(); - Ref<Mesh> mesh; Ref<Shape3D> s = col_shape->get_shape(); BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { - Ref<BoxMesh> box_mesh; - box_mesh.instantiate(); - box_mesh->set_size(box->get_size()); - mesh = box_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + BoxMesh::create_mesh_array(arr, box->get_size()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); if (capsule) { - Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instantiate(); - capsule_mesh->set_radius(capsule->get_radius()); - capsule_mesh->set_height(capsule->get_height()); - mesh = capsule_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s); if (cylinder) { - Ref<CylinderMesh> cylinder_mesh; - cylinder_mesh.instantiate(); - cylinder_mesh->set_height(cylinder->get_height()); - cylinder_mesh->set_bottom_radius(cylinder->get_radius()); - cylinder_mesh->set_top_radius(cylinder->get_radius()); - mesh = cylinder_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s); if (sphere) { - Ref<SphereMesh> sphere_mesh; - sphere_mesh.instantiate(); - sphere_mesh->set_radius(sphere->get_radius()); - sphere_mesh->set_height(sphere->get_radius() * 2.0); - mesh = sphere_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0); + _add_mesh_array(arr, transform, p_vertices, p_indices); } ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s); @@ -254,10 +271,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans _add_faces(faces, transform, p_vertices, p_indices); } } - - if (mesh.is_valid()) { - _add_mesh(mesh, transform, p_vertices, p_indices); - } } } } @@ -284,44 +297,39 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans RID shape = shapes[i + 1]; PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape); Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape); - Ref<Mesh> mesh; switch (type) { case PhysicsServer3D::SHAPE_SPHERE: { real_t radius = data; - Ref<SphereMesh> sphere_mesh; - sphere_mesh.instantiate(); - sphere_mesh->set_radius(radius); - sphere_mesh->set_height(radius * 2.0); - mesh = sphere_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + SphereMesh::create_mesh_array(arr, radius, radius * 2.0); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_BOX: { Vector3 extents = data; - Ref<BoxMesh> box_mesh; - box_mesh.instantiate(); - box_mesh->set_size(2.0 * extents); - mesh = box_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + BoxMesh::create_mesh_array(arr, extents * 2.0); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_CAPSULE: { Dictionary dict = data; real_t radius = dict["radius"]; real_t height = dict["height"]; - Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instantiate(); - capsule_mesh->set_radius(radius); - capsule_mesh->set_height(height); - mesh = capsule_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CapsuleMesh::create_mesh_array(arr, radius, height); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_CYLINDER: { Dictionary dict = data; real_t radius = dict["radius"]; real_t height = dict["height"]; - Ref<CylinderMesh> cylinder_mesh; - cylinder_mesh.instantiate(); - cylinder_mesh->set_height(height); - cylinder_mesh->set_bottom_radius(radius); - cylinder_mesh->set_top_radius(radius); - mesh = cylinder_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CylinderMesh::create_mesh_array(arr, radius, radius, height); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_CONVEX_POLYGON: { PackedVector3Array vertices = data; @@ -354,10 +362,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans WARN_PRINT("Unsupported collision shape type."); } break; } - - if (mesh.is_valid()) { - _add_mesh(mesh, shapes[i], p_vertices, p_indices); - } } } } diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h index 21f7a4941b..8cc1531b53 100644 --- a/modules/navigation/navigation_mesh_generator.h +++ b/modules/navigation/navigation_mesh_generator.h @@ -51,6 +51,7 @@ protected: static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_vertices); static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); + static void _add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); diff --git a/modules/noise/noise.h b/modules/noise/noise.h index c05bc057da..853c24b485 100644 --- a/modules/noise/noise.h +++ b/modules/noise/noise.h @@ -39,7 +39,7 @@ class Noise : public Resource { // Helper struct for get_seamless_image(). See comments in .cpp for usage. template <typename T> struct img_buff { - T *img; + T *img = nullptr; int width; // Array dimensions & default modulo for image. int height; int offset_x; // Offset index location on image (wrapped by specified modulo). @@ -101,6 +101,7 @@ class Noise : public Resource { on Source it's translated to corner of Q1/s3 unless the ALT_XY modulo moves it to Q4 */ + ERR_FAIL_COND_V(p_blend_skirt < 0, Ref<Image>()); int skirt_width = MAX(1, p_width * p_blend_skirt); int skirt_height = MAX(1, p_height * p_blend_skirt); diff --git a/modules/noise/noise_texture.cpp b/modules/noise/noise_texture.cpp index 3721043a09..276335797a 100644 --- a/modules/noise/noise_texture.cpp +++ b/modules/noise/noise_texture.cpp @@ -119,7 +119,7 @@ void NoiseTexture::_thread_done(const Ref<Image> &p_image) { } void NoiseTexture::_thread_function(void *p_ud) { - NoiseTexture *tex = (NoiseTexture *)p_ud; + NoiseTexture *tex = static_cast<NoiseTexture *>(p_ud); tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture()); } diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 32cab1bef1..ff320236a7 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -83,5 +83,8 @@ if env["vulkan"]: env.modules_sources += module_obj +if env["tools"]: + SConscript("editor/SCsub") + # Needed to force rebuilding the module files when the thirdparty library is updated. env.Depends(module_obj, thirdparty_obj) diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp index 59ee3f4292..359975a480 100644 --- a/modules/openxr/action_map/openxr_action.cpp +++ b/modules/openxr/action_map/openxr_action.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "openxr_action.h" +#include "openxr_action_set.h" void OpenXRAction::_bind_methods() { ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name); @@ -62,6 +63,16 @@ Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_loc return action; } +String OpenXRAction::get_name_with_set() const { + String name = get_name(); + + if (action_set != nullptr) { + name = action_set->get_name() + "/" + name; + } + + return name; +} + void OpenXRAction::set_localized_name(const String p_localized_name) { localized_name = p_localized_name; } @@ -86,6 +97,18 @@ PackedStringArray OpenXRAction::get_toplevel_paths() const { return toplevel_paths; } +void OpenXRAction::add_toplevel_path(const String p_toplevel_path) { + if (!toplevel_paths.has(p_toplevel_path)) { + toplevel_paths.push_back(p_toplevel_path); + } +} + +void OpenXRAction::rem_toplevel_path(const String p_toplevel_path) { + if (toplevel_paths.has(p_toplevel_path)) { + toplevel_paths.erase(p_toplevel_path); + } +} + void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) { toplevel_paths = p_toplevel_paths.split(",", false); } diff --git a/modules/openxr/action_map/openxr_action.h b/modules/openxr/action_map/openxr_action.h index e2cfe79e64..5e57f89133 100644 --- a/modules/openxr/action_map/openxr_action.h +++ b/modules/openxr/action_map/openxr_action.h @@ -33,6 +33,8 @@ #include "core/io/resource.h" +class OpenXRActionSet; + class OpenXRAction : public Resource { GDCLASS(OpenXRAction, Resource); @@ -43,6 +45,7 @@ public: OPENXR_ACTION_VECTOR2, OPENXR_ACTION_POSE, OPENXR_ACTION_HAPTIC, + OPENXR_ACTION_MAX }; private: @@ -52,21 +55,31 @@ private: PackedStringArray toplevel_paths; protected: + friend class OpenXRActionSet; + + OpenXRActionSet *action_set = nullptr; // action belongs to this action set. + static void _bind_methods(); public: - static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); + static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); // Helper function to add and configure an action + OpenXRActionSet *get_action_set() const { return action_set; } // Get the action set this action belongs to + + String get_name_with_set() const; // Retrieve the name of this action as <action_set>/<action> + + void set_localized_name(const String p_localized_name); // Set the localized name of this action + String get_localized_name() const; // Get the localized name of this action - void set_localized_name(const String p_localized_name); - String get_localized_name() const; + void set_action_type(const ActionType p_action_type); // Set the type of this action + ActionType get_action_type() const; // Get the type of this action - void set_action_type(const ActionType p_action_type); - ActionType get_action_type() const; + void set_toplevel_paths(const PackedStringArray p_toplevel_paths); // Set the toplevel paths of this action + PackedStringArray get_toplevel_paths() const; // Get the toplevel paths of this action - void set_toplevel_paths(const PackedStringArray p_toplevel_paths); - PackedStringArray get_toplevel_paths() const; + void add_toplevel_path(const String p_toplevel_path); // Add a top level path to this action + void rem_toplevel_path(const String p_toplevel_path); // Remove a toplevel path from this action - void parse_toplevel_paths(const String p_toplevel_paths); + void parse_toplevel_paths(const String p_toplevel_paths); // Parse and set the top level paths from a comma separated string }; VARIANT_ENUM_CAST(OpenXRAction::ActionType); diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index e14c68079d..2ba33419d7 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -35,6 +35,9 @@ void OpenXRActionMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets"); + ClassDB::bind_method(D_METHOD("get_action_set_count"), &OpenXRActionMap::get_action_set_count); + ClassDB::bind_method(D_METHOD("find_action_set", "name"), &OpenXRActionMap::find_action_set); + ClassDB::bind_method(D_METHOD("get_action_set", "idx"), &OpenXRActionMap::get_action_set); ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set); ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set); @@ -42,6 +45,9 @@ void OpenXRActionMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles"); + ClassDB::bind_method(D_METHOD("get_interaction_profile_count"), &OpenXRActionMap::get_interaction_profile_count); + ClassDB::bind_method(D_METHOD("find_interaction_profile", "name"), &OpenXRActionMap::find_interaction_profile); + ClassDB::bind_method(D_METHOD("get_interaction_profile", "idx"), &OpenXRActionMap::get_interaction_profile); ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile); ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile); @@ -56,6 +62,27 @@ Array OpenXRActionMap::get_action_sets() const { return action_sets; } +int OpenXRActionMap::get_action_set_count() const { + return action_sets.size(); +} + +Ref<OpenXRActionSet> OpenXRActionMap::find_action_set(String p_name) const { + for (int i = 0; i < action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = action_sets[i]; + if (action_set->get_name() == p_name) { + return action_set; + } + } + + return Ref<OpenXRActionSet>(); +} + +Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, action_sets.size(), Ref<OpenXRActionSet>()); + + return action_sets[p_idx]; +} + void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) { ERR_FAIL_COND(p_action_set.is_null()); @@ -79,6 +106,27 @@ Array OpenXRActionMap::get_interaction_profiles() const { return interaction_profiles; } +int OpenXRActionMap::get_interaction_profile_count() const { + return interaction_profiles.size(); +} + +Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const { + for (int i = 0; i < interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i]; + if (interaction_profile->get_interaction_profile_path() == p_path) { + return interaction_profile; + } + } + + return Ref<OpenXRInteractionProfile>(); +} + +Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, interaction_profiles.size(), Ref<OpenXRInteractionProfile>()); + + return interaction_profiles[p_idx]; +} + void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) { ERR_FAIL_COND(p_interaction_profile.is_null()); @@ -178,27 +226,6 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our HP MR controller profile - profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); - profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); - profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); - // hpmr controllers have no select button we can use - profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); - // hpmr controllers only register click, not touch, on our a/b/x/y buttons - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand - profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - // primary on our hpmr controller is our thumbstick - profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); - profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); - // No secondary on our hpmr controller - profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); - add_interaction_profile(profile); - // Create our Meta touch controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); @@ -249,12 +276,185 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); + + // Note, the following profiles are all part of extensions. + // We include these regardless of whether the extension is active. + // We want our action map to be as complete as possible so our game is as portable as possible. + // It is very possible these will in due time become core. + + // Create our HP MR controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // hpmr controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // hpmr controllers only register click, not touch, on our a/b/x/y buttons + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our hpmr controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // No secondary on our hpmr controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Samsung Odyssey controller profile, + // Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller. + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // Odyssey controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // Odyssey controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Odyssey controller is our thumbstick, no touch + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // secondary on our Odyssey controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive Cosmos controller + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Cosmos controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // No secondary on our cosmos controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive Focus 3 controller + // Note, Vive Focus 3 currently is not yet supported as a stand alone device + // however HTC currently has a beta OpenXR runtime in testing we may support in the near future + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Focus 3 controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // We only have a thumb rest + profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Huawei controller + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + // primary on our Huawei controller is our trackpad + profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); } void OpenXRActionMap::create_editor_action_sets() { // TODO implement } +Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const { + PackedStringArray paths = p_path.split("/", false); + ERR_FAIL_COND_V(paths.size() != 2, Ref<OpenXRAction>()); + + Ref<OpenXRActionSet> action_set = find_action_set(paths[0]); + if (action_set.is_valid()) { + return action_set->get_action(paths[1]); + } + + return Ref<OpenXRAction>(); +} + +void OpenXRActionMap::remove_action(const String p_path) { + Ref<OpenXRAction> action = get_action(p_path); + if (action.is_valid()) { + 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 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()); + + if (profile != nullptr) { + for (int j = 0; j < ip->get_binding_count(); j++) { + Ref<OpenXRIPBinding> binding = ip->get_binding(j); + if (binding->get_action() == p_action) { + PackedStringArray paths = binding->get_paths(); + + for (int k = 0; k < paths.size(); k++) { + const OpenXRDefs::IOPath *io_path = profile->get_io_path(paths[k]); + if (io_path != nullptr) { + String top_path = String(io_path->top_level_path->openxr_path); + + if (!arr.has(top_path)) { + arr.push_back(top_path); + } + } + } + } + } + } + } + + print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr); + + return arr; +} + OpenXRActionMap::~OpenXRActionMap() { action_sets.clear(); interaction_profiles.clear(); diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h index 866e170468..dcd8fc71aa 100644 --- a/modules/openxr/action_map/openxr_action_map.h +++ b/modules/openxr/action_map/openxr_action_map.h @@ -33,6 +33,7 @@ #include "core/io/resource.h" +#include "openxr_action.h" #include "openxr_action_set.h" #include "openxr_interaction_profile.h" @@ -47,20 +48,33 @@ protected: static void _bind_methods(); public: - void set_action_sets(Array p_action_sets); - Array get_action_sets() const; + void set_action_sets(Array p_action_sets); // Set our actions sets by providing an array with action sets (for loading from resource) + Array get_action_sets() const; // Get our action sets as an array (for saving to resource) - void add_action_set(Ref<OpenXRActionSet> p_action_set); - void remove_action_set(Ref<OpenXRActionSet> p_action_set); + int get_action_set_count() const; // Retrieve the number of action sets we have + Ref<OpenXRActionSet> find_action_set(String p_name) const; // Find an action set by name + Ref<OpenXRActionSet> get_action_set(int p_idx) const; // Retrieve an action set by index + void add_action_set(Ref<OpenXRActionSet> p_action_set); // Add an action set to our action map + void remove_action_set(Ref<OpenXRActionSet> p_action_set); // Remove an action set from our action map - void set_interaction_profiles(Array p_interaction_profiles); - Array get_interaction_profiles() const; + void set_interaction_profiles(Array p_interaction_profiles); // Set our interaction profiles by providing an array (for loading from resource) + Array get_interaction_profiles() const; // Get our interaction profiles as an array (for saving to resource) - void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); - void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); + int get_interaction_profile_count() const; // Retrieve the number of interaction profiles we have + Ref<OpenXRInteractionProfile> find_interaction_profile(String p_path) const; // Find an interaction profile by path + Ref<OpenXRInteractionProfile> get_interaction_profile(int p_idx) const; // Retrieve an interaction profile by index + void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // Add an interaction profile to our action map + void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // remove an interaction profile from our action map - void create_default_action_sets(); - void create_editor_action_sets(); + void create_default_action_sets(); // Create our default action set for runtime + void create_editor_action_sets(); // Create our action set for the editor + + // 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 + + // 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 ~OpenXRActionMap(); }; diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp index 465a709b60..be45218300 100644 --- a/modules/openxr/action_map/openxr_action_set.cpp +++ b/modules/openxr/action_map/openxr_action_set.cpp @@ -39,6 +39,7 @@ void OpenXRActionSet::_bind_methods() { ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority); ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority"); + ClassDB::bind_method(D_METHOD("get_action_count"), &OpenXRActionSet::get_action_count); ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions); ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions"); @@ -75,18 +76,54 @@ int OpenXRActionSet::get_priority() const { return priority; } +int OpenXRActionSet::get_action_count() const { + return actions.size(); +} + +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 + for (int i = 0; i < actions.size(); i++) { + Ref<OpenXRAction> action = actions[i]; + action->action_set = nullptr; + } + actions.clear(); +} + void OpenXRActionSet::set_actions(Array p_actions) { - actions = p_actions; + // Any actions not retained in p_actions should be freed automatically, those held within our Array will have be relinked to our action set. + clear_actions(); + + for (int i = 0; i < p_actions.size(); i++) { + // add them anew so we verify our action_set pointer + add_action(p_actions[i]); + } } Array OpenXRActionSet::get_actions() const { return actions; } +Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const { + for (int i = 0; i < actions.size(); i++) { + Ref<OpenXRAction> action = actions[i]; + if (action->get_name() == p_name) { + return action; + } + } + + return Ref<OpenXRAction>(); +} + void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) { ERR_FAIL_COND(p_action.is_null()); if (actions.find(p_action) == -1) { + if (p_action->action_set && p_action->action_set != this) { + // action should only relate to our action set + p_action->action_set->remove_action(p_action); + } + + p_action->action_set = this; actions.push_back(p_action); } } @@ -95,6 +132,9 @@ void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) { int idx = actions.find(p_action); if (idx != -1) { actions.remove_at(idx); + + 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; } } @@ -107,5 +147,5 @@ Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char } OpenXRActionSet::~OpenXRActionSet() { - actions.clear(); + clear_actions(); } diff --git a/modules/openxr/action_map/openxr_action_set.h b/modules/openxr/action_map/openxr_action_set.h index 012a088b1c..b1d7168894 100644 --- a/modules/openxr/action_map/openxr_action_set.h +++ b/modules/openxr/action_map/openxr_action_set.h @@ -43,26 +43,31 @@ private: int priority = 0; Array actions; + void clear_actions(); protected: static void _bind_methods(); public: - static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); + static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); // Helper function for adding and setting up an action set - void set_localized_name(const String p_localized_name); - String get_localized_name() const; + void set_localized_name(const String p_localized_name); // Set the localized name of this action set + String get_localized_name() const; // Get the localized name of this action set - void set_priority(const int p_priority); - int get_priority() const; + void set_priority(const int p_priority); // Set the priority of this action set + int get_priority() const; // Get the priority of this action set - void set_actions(Array p_actions); - Array get_actions() const; + int get_action_count() const; // Retrieve the number of actions in our action set + void set_actions(Array p_actions); // Set our actions using an array of actions (for loading a resource) + Array get_actions() const; // Get our actions as an array (for saving a resource) - void add_action(Ref<OpenXRAction> p_action); - void remove_action(Ref<OpenXRAction> p_action); + Ref<OpenXRAction> get_action(const String p_name) const; // Retrieve an action by name + void add_action(Ref<OpenXRAction> p_action); // Add a new action to our action set + void remove_action(Ref<OpenXRAction> p_action); // remove a action from our action set - Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); + Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); // Helper function for adding and setting up an action + + // TODO add validation to display in the interface that checks if we have duplicate action names within our action set ~OpenXRActionSet(); }; diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp new file mode 100644 index 0000000000..e10326449c --- /dev/null +++ b/modules/openxr/action_map/openxr_defs.cpp @@ -0,0 +1,493 @@ +/*************************************************************************/ +/* 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] = { + { "Left hand controller", "/user/hand/left" }, + { "Right hand controller", "/user/hand/right" }, +}; + +// 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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, + + { "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 }, +}; + +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 + }, +}; + +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 new file mode 100644 index 0000000000..dbda4757f1 --- /dev/null +++ b/modules/openxr/action_map/openxr_defs.h @@ -0,0 +1,103 @@ +/*************************************************************************/ +/* 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 { + OPENXR_LEFT_HAND, + OPENXR_RIGHT_HAND, + 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 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 bc33814f17..342c36cdff 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -35,9 +35,14 @@ void OpenXRIPBinding::_bind_methods() { ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action"); + ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count); ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths"); + + ClassDB::bind_method(D_METHOD("has_path"), &OpenXRIPBinding::has_path); + ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path); + ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path); } Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) { @@ -59,6 +64,10 @@ Ref<OpenXRAction> OpenXRIPBinding::get_action() const { return action; } +int OpenXRIPBinding::get_path_count() const { + return paths.size(); +} + void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { paths = p_paths; } @@ -71,6 +80,22 @@ void OpenXRIPBinding::parse_paths(const String p_paths) { paths = p_paths.split(",", false); } +bool OpenXRIPBinding::has_path(const String p_path) const { + return paths.has(p_path); +} + +void OpenXRIPBinding::add_path(const String p_path) { + if (!paths.has(p_path)) { + paths.push_back(p_path); + } +} + +void OpenXRIPBinding::remove_path(const String p_path) { + if (paths.has(p_path)) { + paths.erase(p_path); + } +} + OpenXRIPBinding::~OpenXRIPBinding() { action.unref(); } @@ -80,6 +105,8 @@ void OpenXRInteractionProfile::_bind_methods() { ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path); ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path"); + ClassDB::bind_method(D_METHOD("get_binding_count"), &OpenXRInteractionProfile::get_binding_count); + ClassDB::bind_method(D_METHOD("get_binding", "index"), &OpenXRInteractionProfile::get_binding); ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings); ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings"); @@ -101,18 +128,43 @@ String OpenXRInteractionProfile::get_interaction_profile_path() const { return interaction_profile_path; } +int OpenXRInteractionProfile::get_binding_count() const { + return bindings.size(); +} + +Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const { + ERR_FAIL_INDEX_V(p_index, bindings.size(), Ref<OpenXRIPBinding>()); + + return bindings[p_index]; +} + void OpenXRInteractionProfile::set_bindings(Array p_bindings) { bindings = p_bindings; + + // TODO add check here that our bindings don't contain duplicate actions } Array OpenXRInteractionProfile::get_bindings() const { return bindings; } +Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const { + for (int i = 0; i < bindings.size(); i++) { + Ref<OpenXRIPBinding> binding = bindings[i]; + if (binding->get_action() == p_action) { + return binding; + } + } + + return Ref<OpenXRIPBinding>(); +} + void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) { ERR_FAIL_COND(p_binding.is_null()); if (bindings.find(p_binding) == -1) { + 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); } } @@ -131,6 +183,15 @@ void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, add_binding(binding); } +void OpenXRInteractionProfile::remove_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) { + remove_binding(binding); + } + } +} + 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 abbc429e7d..46b1bda50f 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.h +++ b/modules/openxr/action_map/openxr_interaction_profile.h @@ -34,6 +34,7 @@ #include "core/io/resource.h" #include "openxr_action.h" +#include "openxr_defs.h" class OpenXRIPBinding : public Resource { GDCLASS(OpenXRIPBinding, Resource); @@ -46,15 +47,22 @@ protected: static void _bind_methods(); public: - static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); + static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Helper function for adding a new binding - void set_action(const Ref<OpenXRAction> p_action); - Ref<OpenXRAction> get_action() const; + void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding + Ref<OpenXRAction> get_action() const; // Get the action for this binding - void set_paths(const PackedStringArray p_paths); - PackedStringArray get_paths() const; + int get_path_count() const; // Get the number of io paths + void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource) + PackedStringArray get_paths() const; // Get our paths (for saving to resource) - void parse_paths(const String p_paths); + void parse_paths(const String p_paths); // Parse a comma separated string of io paths. + + bool has_path(const String p_path) const; // Has this io path + void add_path(const String p_path); // Add an io path + void remove_path(const String p_path); // Remove an io path + + // TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path ~OpenXRIPBinding(); }; @@ -70,18 +78,22 @@ protected: static void _bind_methods(); public: - static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); + static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); // Helper function to create a new interaction profile - void set_interaction_profile_path(const String p_input_profile_path); - String get_interaction_profile_path() const; + void set_interaction_profile_path(const String p_input_profile_path); // Set our input profile path + String get_interaction_profile_path() const; // get our input profile path - void set_bindings(Array p_bindings); - Array get_bindings() const; + int get_binding_count() const; // Retrieve the number of bindings in this profile path + Ref<OpenXRIPBinding> get_binding(int p_index) const; + void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource) + Array get_bindings() const; // Get the bindings (for saving to a resource) - void add_binding(Ref<OpenXRIPBinding> p_binding); - void remove_binding(Ref<OpenXRIPBinding> p_binding); + Ref<OpenXRIPBinding> get_binding_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action + void add_binding(Ref<OpenXRIPBinding> p_binding); // Add a binding object + void remove_binding(Ref<OpenXRIPBinding> p_binding); // Remove a binding object - void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); + 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 ~OpenXRInteractionProfile(); }; diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml index 4dd2b83ca7..a29d10be41 100644 --- a/modules/openxr/doc_classes/OpenXRActionMap.xml +++ b/modules/openxr/doc_classes/OpenXRActionMap.xml @@ -31,6 +31,46 @@ Setup this action set with our default actions. </description> </method> + <method name="find_action_set" qualifiers="const"> + <return type="OpenXRActionSet" /> + <argument index="0" name="name" type="String" /> + <description> + Retrieve an action set by name. + </description> + </method> + <method name="find_interaction_profile" qualifiers="const"> + <return type="OpenXRInteractionProfile" /> + <argument index="0" name="name" type="String" /> + <description> + Find an interaction profile by its name (path). + </description> + </method> + <method name="get_action_set" qualifiers="const"> + <return type="OpenXRActionSet" /> + <argument index="0" name="idx" type="int" /> + <description> + Retrieve the action set at this index. + </description> + </method> + <method name="get_action_set_count" qualifiers="const"> + <return type="int" /> + <description> + Retrieve the number of actions sets in our action map. + </description> + </method> + <method name="get_interaction_profile" qualifiers="const"> + <return type="OpenXRInteractionProfile" /> + <argument index="0" name="idx" type="int" /> + <description> + Get the interaction profile at this index. + </description> + </method> + <method name="get_interaction_profile_count" qualifiers="const"> + <return type="int" /> + <description> + Retrieve the number of interaction profiles in our action map. + </description> + </method> <method name="remove_action_set"> <return type="void" /> <argument index="0" name="action_set" type="OpenXRActionSet" /> @@ -48,8 +88,10 @@ </methods> <members> <member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]"> + Collection of [OpenXRActionSet]s that are part of this action map. </member> <member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]"> + Collection of [OpenXRInteractionProfile]s that are part of this action map. </member> </members> </class> diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml index 5a87de463e..55cc0aaad4 100644 --- a/modules/openxr/doc_classes/OpenXRActionSet.xml +++ b/modules/openxr/doc_classes/OpenXRActionSet.xml @@ -5,8 +5,7 @@ </brief_description> <description> Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle. - Action sets can contain the same actions, or actions with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active. - Note that the name of the resource is used to identify the action set within OpenXR. + Action sets can contain the same action with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active. </description> <tutorials> </tutorials> @@ -18,6 +17,12 @@ Add an action to this action set. </description> </method> + <method name="get_action_count" qualifiers="const"> + <return type="int" /> + <description> + Retrieve the number of actions in our action set. + </description> + </method> <method name="remove_action"> <return type="void" /> <argument index="0" name="action" type="OpenXRAction" /> diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml index 3fdcde5eb5..9e1176874a 100644 --- a/modules/openxr/doc_classes/OpenXRIPBinding.xml +++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml @@ -4,13 +4,42 @@ Defines a binding between an [OpenXRAction] and an XR input or output. </brief_description> <description> - This binding resource binds an OpenXR action to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". + This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". </description> <tutorials> </tutorials> + <methods> + <method name="add_path"> + <return type="void" /> + <argument index="0" name="path" type="String" /> + <description> + Add an input/output path to this binding. + </description> + </method> + <method name="get_path_count" qualifiers="const"> + <return type="int" /> + <description> + Get the number of input/output paths in this binding. + </description> + </method> + <method name="has_path" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="arg0" type="String" /> + <description> + Returns [code]true[/code] if this input/output path is part of this binding. + </description> + </method> + <method name="remove_path"> + <return type="void" /> + <argument index="0" name="path" type="String" /> + <description> + Removes this input/output path from this binding. + </description> + </method> + </methods> <members> <member name="action" type="OpenXRAction" setter="set_action" getter="get_action"> - Action that is bound to these paths. + [OpenXRAction] that is bound to these paths. </member> <member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()"> Paths that define the inputs or outputs bound on the device. diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml index a8629caae4..71c0db44ed 100644 --- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml +++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml @@ -9,6 +9,21 @@ </description> <tutorials> </tutorials> + <methods> + <method name="get_binding" qualifiers="const"> + <return type="OpenXRIPBinding" /> + <argument index="0" name="index" type="int" /> + <description> + Retrieve the binding at this index. + </description> + </method> + <method name="get_binding_count" qualifiers="const"> + <return type="int" /> + <description> + Get the number of bindings in this interaction profile. + </description> + </method> + </methods> <members> <member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]"> Action bindings for this interaction profile. diff --git a/modules/openxr/editor/SCsub b/modules/openxr/editor/SCsub new file mode 100644 index 0000000000..ccf67a80d0 --- /dev/null +++ b/modules/openxr/editor/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp new file mode 100644 index 0000000000..e2a4f67f16 --- /dev/null +++ b/modules/openxr/editor/openxr_action_editor.cpp @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* openxr_action_editor.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_action_editor.h" + +void OpenXRActionEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor"))); +} + +void OpenXRActionEditor::_theme_changed() { + rem_action->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); +} + +void OpenXRActionEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + _theme_changed(); + } break; + } +} + +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); + } + action->set_name(p_new_text); +} + +void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_text) { + action->set_localized_name(p_new_text); +} + +void OpenXRActionEditor::_on_item_selected(int p_idx) { + ERR_FAIL_COND(p_idx < 0); + ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX); + + action->set_action_type(OpenXRAction::ActionType(p_idx)); +} + +void OpenXRActionEditor::_on_remove_action() { + emit_signal("remove", this); +} + +OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) { + action = p_action; + + set_h_size_flags(Control::SIZE_EXPAND_FILL); + + action_name = memnew(LineEdit); + action_name->set_text(action->get_name()); + action_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_name_changed)); + add_child(action_name); + + action_localized_name = memnew(LineEdit); + action_localized_name->set_text(action->get_localized_name()); + action_localized_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); + 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); + + // maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings? + + rem_action = memnew(Button); + rem_action->set_tooltip(TTR("Remove action")); + rem_action->connect("pressed", callable_mp(this, &OpenXRActionEditor::_on_remove_action)); + rem_action->set_flat(true); + add_child(rem_action); +} diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h new file mode 100644 index 0000000000..6e1b7ab779 --- /dev/null +++ b/modules/openxr/editor/openxr_action_editor.h @@ -0,0 +1,67 @@ +/*************************************************************************/ +/* openxr_action_editor.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_ACTION_EDITOR_H +#define OPENXR_ACTION_EDITOR_H + +#include "../action_map/openxr_action.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/option_button.h" +#include "scene/gui/text_edit.h" + +class OpenXRActionEditor : public HBoxContainer { + GDCLASS(OpenXRActionEditor, HBoxContainer); + +private: + Ref<OpenXRAction> action; + + LineEdit *action_name = nullptr; + LineEdit *action_localized_name = nullptr; + OptionButton *action_type = nullptr; + Button *rem_action = nullptr; + + void _theme_changed(); + void _on_action_name_changed(const String p_new_text); + void _on_action_localized_name_changed(const String p_new_text); + void _on_item_selected(int p_idx); + void _on_remove_action(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + Ref<OpenXRAction> get_action() { return action; }; + OpenXRActionEditor(Ref<OpenXRAction> p_action); +}; + +#endif // !OPENXR_ACTION_EDITOR_H diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp new file mode 100644 index 0000000000..6e9a2e1b61 --- /dev/null +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -0,0 +1,370 @@ +/*************************************************************************/ +/* openxr_action_map_editor.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_action_map_editor.h" + +#include "core/config/project_settings.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" + +// TODO implement redo/undo system + +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); +} + +void OpenXRActionMapEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + for (int i = 0; i < tabs->get_child_count(); i++) { + Control *tab = static_cast<Control *>(tabs->get_child(i)); + if (tab) { + tab->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + } + } + } break; + + case NOTIFICATION_READY: { + _update_action_sets(); + _update_interaction_profiles(); + } break; + } +} + +OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(Ref<OpenXRActionSet> p_action_set) { + ERR_FAIL_COND_V(p_action_set.is_null(), nullptr); + + 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... + if (action_map.is_valid()) { + Array action_sets = action_map->get_action_sets(); + for (int i = 0; i < action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = action_sets[i]; + _add_action_set_editor(action_set); + } + } +} + +OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile) { + ERR_FAIL_COND_V(p_interaction_profile.is_null(), nullptr); + + String profile_path = p_interaction_profile->get_interaction_profile_path(); + + // need to instance the correct editor for our profile + OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr; + if (profile_path == "placeholder_text") { + // instance specific editor for this type + } else { + // instance generic editor + new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile)); + } + + // now add it in.. + ERR_FAIL_NULL_V(new_profile_editor, nullptr); + tabs->add_child(new_profile_editor); + new_profile_editor->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), 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_delete(); + } + + // in with the new... + if (action_map.is_valid()) { + Array new_interaction_profiles = action_map->get_interaction_profiles(); + for (int i = 0; i < new_interaction_profiles.size(); i++) { + Ref<OpenXRInteractionProfile> interaction_profile = new_interaction_profiles[i]; + _add_interaction_profile_editor(interaction_profile); + } + } +} + +OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(String p_name) { + ERR_FAIL_COND_V(action_map.is_null(), nullptr); + Ref<OpenXRActionSet> new_action_set; + + // add our new action set + new_action_set.instantiate(); + new_action_set->set_name(p_name); + new_action_set->set_localized_name(p_name); + action_map->add_action_set(new_action_set); + + // update our editor right away + return _add_action_set_editor(new_action_set); +} + +void OpenXRActionMapEditor::_remove_action_set(String p_name) { + ERR_FAIL_COND(action_map.is_null()); + 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!"); + } + + // now we remove it + action_map->remove_action_set(action_set); +} + +void OpenXRActionMapEditor::_on_add_action_set() { + ERR_FAIL_COND(action_map.is_null()); + String new_name = "New"; + int count = 0; + + while (action_map->find_action_set(new_name).is_valid()) { + new_name = "New_" + itos(count++); + } + + OpenXRActionSetEditor *new_action_set_editor = _add_action_set(new_name); + + // Make sure our action set is the current tab + tabs->set_current_tab(0); + + call_deferred("_set_focus_on_action_set", new_action_set_editor); +} + +void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) { + // Scroll down to our new entry + actionsets_scroll->ensure_control_visible(p_action_set_editor); + + // Set focus on this entry + p_action_set_editor->set_focus_on_entry(); +} + +void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) { + ERR_FAIL_COND(action_map.is_null()); + + OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(p_action_set_editor); + ERR_FAIL_NULL(action_set_editor); + ERR_FAIL_COND(action_set_editor->get_parent() != actionsets_vb); + 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_delete(); +} + +void OpenXRActionMapEditor::_on_action_removed() { + // make sure our interaction profiles are updated + _update_interaction_profiles(); +} + +void OpenXRActionMapEditor::_on_add_interaction_profile() { + ERR_FAIL_COND(action_map.is_null()); + + PackedStringArray already_selected; + + for (int i = 0; i < action_map->get_interaction_profile_count(); i++) { + already_selected.push_back(action_map->get_interaction_profile(i)->get_interaction_profile_path()); + } + + select_interaction_profile_dialog->open(already_selected); +} + +void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path) { + ERR_FAIL_COND(action_map.is_null()); + + Ref<OpenXRInteractionProfile> new_profile; + new_profile.instantiate(); + new_profile->set_interaction_profile_path(p_path); + action_map->add_interaction_profile(new_profile); + + _add_interaction_profile_editor(new_profile); + + 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) { + action_map.instantiate(); + action_map->create_default_action_sets(); + } else { + EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an OpenXR action map.")); + + edited_path = ""; + header_label->set_text(""); + return; + } + } + + edited_path = p_path; + header_label->set_text(TTR("OpenXR Action map:") + " " + p_path.get_file()); +} + +void OpenXRActionMapEditor::_on_save_action_map() { + Error err = ResourceSaver::save(edited_path, action_map); + if (err != OK) { + EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), edited_path)); + return; + } + + _update_action_sets(); + _update_interaction_profiles(); +} + +void OpenXRActionMapEditor::_on_reset_to_default_layout() { + // create a new one + action_map.unref(); + action_map.instantiate(); + action_map->create_default_action_sets(); + + _update_action_sets(); + _update_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); + + Ref<OpenXRInteractionProfile> interaction_profile = profile_editor->get_interaction_profile(); + ERR_FAIL_COND(interaction_profile.is_null()); + + action_map->remove_interaction_profile(interaction_profile); + tabs->remove_child(profile_editor); + profile_editor->queue_delete(); +} + +void OpenXRActionMapEditor::open_action_map(String p_path) { + EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + + _load_action_map(p_path); + + _update_action_sets(); + _update_interaction_profiles(); +} + +OpenXRActionMapEditor::OpenXRActionMapEditor() { + set_custom_minimum_size(Size2(0.0, 300.0)); + + top_hb = memnew(HBoxContainer); + add_child(top_hb); + + header_label = memnew(Label); + header_label->set_text(String(TTR("Action Map"))); + header_label->set_clip_text(true); + header_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + top_hb->add_child(header_label); + + add_action_set = memnew(Button); + add_action_set->set_text(TTR("Add Action Set")); + add_action_set->set_tooltip(TTR("Add an action set.")); + add_action_set->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set)); + top_hb->add_child(add_action_set); + + add_interaction_profile = memnew(Button); + add_interaction_profile->set_text(TTR("Add profile")); + add_interaction_profile->set_tooltip(TTR("Add an interaction profile.")); + add_interaction_profile->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile)); + top_hb->add_child(add_interaction_profile); + + VSeparator *vseparator = memnew(VSeparator); + top_hb->add_child(vseparator); + + save_as = memnew(Button); + save_as->set_text(TTR("Save")); + save_as->set_tooltip(TTR("Save this OpenXR action map.")); + save_as->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map)); + top_hb->add_child(save_as); + + _default = memnew(Button); + _default->set_text(TTR("Reset to Default")); + _default->set_tooltip(TTR("Reset to default OpenXR action map.")); + _default->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout)); + top_hb->add_child(_default); + + tabs = memnew(TabContainer); + tabs->set_h_size_flags(SIZE_EXPAND_FILL); + tabs->set_v_size_flags(SIZE_EXPAND_FILL); + tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed)); + tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed)); + add_child(tabs); + + actionsets_scroll = memnew(ScrollContainer); + actionsets_scroll->set_h_size_flags(SIZE_EXPAND_FILL); + actionsets_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + actionsets_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + tabs->add_child(actionsets_scroll); + actionsets_scroll->set_name(TTR("Action Sets")); + + actionsets_vb = memnew(VBoxContainer); + actionsets_vb->set_h_size_flags(SIZE_EXPAND_FILL); + actionsets_scroll->add_child(actionsets_vb); + + select_interaction_profile_dialog = memnew(OpenXRSelectInteractionProfileDialog); + 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(ProjectSettings::get_singleton()->get("xr/openxr/default_action_map")); +} + +OpenXRActionMapEditor::~OpenXRActionMapEditor() { +} diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h new file mode 100644 index 0000000000..dfc941b500 --- /dev/null +++ b/modules/openxr/editor/openxr_action_map_editor.h @@ -0,0 +1,100 @@ +/*************************************************************************/ +/* openxr_action_map_editor.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_ACTION_MAP_EDITOR_H +#define OPENXR_ACTION_MAP_EDITOR_H + +#include "../action_map/openxr_action_map.h" +#include "../editor/openxr_action_set_editor.h" +#include "../editor/openxr_interaction_profile_editor.h" +#include "../editor/openxr_select_interaction_profile_dialog.h" + +#include "editor/editor_plugin.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/tab_container.h" + +class OpenXRActionMapEditor : public VBoxContainer { + GDCLASS(OpenXRActionMapEditor, VBoxContainer); + +private: + String edited_path; + Ref<OpenXRActionMap> action_map; + Vector<Node *> interaction_profiles; + + HBoxContainer *top_hb = nullptr; + Label *header_label = nullptr; + Button *add_action_set = nullptr; + Button *add_interaction_profile = nullptr; + Button *load = nullptr; + Button *save_as = nullptr; + Button *_default = nullptr; + TabContainer *tabs = nullptr; + ScrollContainer *actionsets_scroll = nullptr; + VBoxContainer *actionsets_vb = nullptr; + OpenXRSelectInteractionProfileDialog *select_interaction_profile_dialog = nullptr; + + OpenXRActionSetEditor *_add_action_set_editor(Ref<OpenXRActionSet> p_action_set); + void _update_action_sets(); + OpenXRInteractionProfileEditorBase *_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile); + void _update_interaction_profiles(); + + OpenXRActionSetEditor *_add_action_set(String p_name); + void _remove_action_set(String p_name); + + void _on_add_action_set(); + void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor); + void _on_remove_action_set(Object *p_action_set_editor); + void _on_action_removed(); + + void _on_add_interaction_profile(); + void _on_interaction_profile_selected(const String p_path); + + void _load_action_map(const String p_path, bool p_create_new_if_missing = false); + void _on_save_action_map(); + void _on_reset_to_default_layout(); + + void _on_tabs_tab_changed(int p_tab); + void _on_tab_button_pressed(int p_tab); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + void open_action_map(String p_path); + + OpenXRActionMapEditor(); + ~OpenXRActionMapEditor(); +}; + +#endif // !OPENXR_ACTION_MAP_EDITOR_H diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp new file mode 100644 index 0000000000..7bf8557c5b --- /dev/null +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -0,0 +1,218 @@ +/*************************************************************************/ +/* openxr_action_set_editor.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_action_set_editor.h" +#include "openxr_action_editor.h" + +void OpenXRActionSetEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_set_editor"))); + ADD_SIGNAL(MethodInfo("action_removed")); +} + +void OpenXRActionSetEditor::_set_fold_icon() { + if (is_expanded) { + fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons"))); + } else { + fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons"))); + } +} + +void OpenXRActionSetEditor::_theme_changed() { + _set_fold_icon(); + add_action->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); +} + +void OpenXRActionSetEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + _theme_changed(); + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + } break; + } +} + +OpenXRActionEditor *OpenXRActionSetEditor::_add_action_editor(Ref<OpenXRAction> p_action) { + OpenXRActionEditor *action_editor = memnew(OpenXRActionEditor(p_action)); + action_editor->connect("remove", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action)); + actions_vb->add_child(action_editor); + + 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); + _set_fold_icon(); +} + +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); + } + action_set->set_name(p_new_text); +} + +void OpenXRActionSetEditor::_on_action_set_localized_name_changed(const String p_new_text) { + action_set->set_localized_name(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); +} + +void OpenXRActionSetEditor::_on_add_action() { + Ref<OpenXRAction> new_action; + + new_action.instantiate(); + new_action->set_name("New"); + new_action->set_localized_name("New"); + action_set->add_action(new_action); + + _add_action_editor(new_action); + + // TODO handle focus +} + +void OpenXRActionSetEditor::_on_remove_action_set() { + emit_signal("remove", this); +} + +void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) { + OpenXRActionEditor *action_editor = Object::cast_to<OpenXRActionEditor>(p_action_editor); + ERR_FAIL_NULL(action_editor); + ERR_FAIL_COND(action_editor->get_parent() != actions_vb); + Ref<OpenXRAction> action = action_editor->get_action(); + ERR_FAIL_COND(action.is_null()); + + // TODO add undo/redo action + + // TODO find where this action is used by our interaction profiles and remove it there + + // 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_delete(); + + // Let action map editor know so we can update our interaction profiles + emit_signal("action_removed"); +} + +void OpenXRActionSetEditor::set_focus_on_entry() { + ERR_FAIL_NULL(action_set_name); + action_set_name->grab_focus(); +} + +OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) { + action_map = p_action_map; + action_set = p_action_set; + + set_h_size_flags(Control::SIZE_EXPAND_FILL); + + panel = memnew(PanelContainer); + panel->set_h_size_flags(Control::SIZE_EXPAND_FILL); + add_child(panel); + + HBoxContainer *panel_hb = memnew(HBoxContainer); + panel_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + panel->add_child(panel_hb); + + fold_btn = memnew(Button); + fold_btn->set_v_size_flags(Control::SIZE_SHRINK_BEGIN); + fold_btn->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand)); + fold_btn->set_flat(true); + panel_hb->add_child(fold_btn); + + main_vb = memnew(VBoxContainer); + main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + panel_hb->add_child(main_vb); + + action_set_hb = memnew(HBoxContainer); + action_set_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(action_set_hb); + + action_set_name = memnew(LineEdit); + action_set_name->set_text(action_set->get_name()); + action_set_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_set_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_name_changed)); + action_set_hb->add_child(action_set_name); + + action_set_localized_name = memnew(LineEdit); + action_set_localized_name->set_text(action_set->get_localized_name()); + action_set_localized_name->set_custom_minimum_size(Size2(150.0, 0.0)); + action_set_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); + action_set_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_localized_name_changed)); + action_set_hb->add_child(action_set_localized_name); + + action_set_priority = memnew(TextEdit); + action_set_priority->set_text(itos(action_set->get_priority())); + action_set_priority->set_custom_minimum_size(Size2(50.0, 0.0)); + action_set_priority->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_priority_changed)); + action_set_hb->add_child(action_set_priority); + + add_action = memnew(Button); + add_action->set_tooltip("Add Action."); + add_action->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_add_action)); + add_action->set_flat(true); + action_set_hb->add_child(add_action); + + rem_action_set = memnew(Button); + rem_action_set->set_tooltip("Remove Action Set."); + rem_action_set->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set)); + rem_action_set->set_flat(true); + action_set_hb->add_child(rem_action_set); + + actions_vb = memnew(VBoxContainer); + actions_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(actions_vb); + + _update_actions(); +} diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h new file mode 100644 index 0000000000..f3960dcbf9 --- /dev/null +++ b/modules/openxr/editor/openxr_action_set_editor.h @@ -0,0 +1,88 @@ +/*************************************************************************/ +/* openxr_action_set_editor.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_ACTION_SET_EDITOR_H +#define OPENXR_ACTION_SET_EDITOR_H + +#include "../action_map/openxr_action_map.h" +#include "../action_map/openxr_action_set.h" +#include "openxr_action_editor.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/text_edit.h" + +class OpenXRActionSetEditor : public HBoxContainer { + GDCLASS(OpenXRActionSetEditor, HBoxContainer); + +private: + Ref<OpenXRActionMap> action_map; + Ref<OpenXRActionSet> action_set; + + bool is_expanded = true; + + PanelContainer *panel = nullptr; + Button *fold_btn = nullptr; + VBoxContainer *main_vb = nullptr; + HBoxContainer *action_set_hb = nullptr; + LineEdit *action_set_name = nullptr; + LineEdit *action_set_localized_name = nullptr; + TextEdit *action_set_priority = nullptr; + Button *add_action = nullptr; + Button *rem_action_set = nullptr; + VBoxContainer *actions_vb = nullptr; + + 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); + void _on_action_set_localized_name_changed(const String p_new_text); + void _on_action_set_priority_changed(const String p_new_text); + void _on_add_action(); + void _on_remove_action_set(); + + void _on_remove_action(Object *p_action_editor); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + Ref<OpenXRActionSet> get_action_set() { return action_set; }; + void set_focus_on_entry(); + + OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set); +}; + +#endif // !OPENXR_ACTION_SET_EDITOR_H diff --git a/modules/openxr/editor/openxr_editor_plugin.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp new file mode 100644 index 0000000000..b87b538511 --- /dev/null +++ b/modules/openxr/editor/openxr_editor_plugin.cpp @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* openxr_editor_plugin.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_editor_plugin.h" + +#include "../action_map/openxr_action_map.h" +#include "editor/editor_node.h" + +void OpenXREditorPlugin::edit(Object *p_node) { + if (Object::cast_to<OpenXRActionMap>(p_node)) { + String path = Object::cast_to<OpenXRActionMap>(p_node)->get_path(); + if (path.is_resource_file()) { + action_map_editor->open_action_map(path); + } + } +} + +bool OpenXREditorPlugin::handles(Object *p_node) const { + return (Object::cast_to<OpenXRActionMap>(p_node) != nullptr); +} + +void OpenXREditorPlugin::make_visible(bool p_visible) { +} + +OpenXREditorPlugin::OpenXREditorPlugin() { + action_map_editor = memnew(OpenXRActionMapEditor); + EditorNode::get_singleton()->add_bottom_panel_item(TTR("OpenXR Action Map"), action_map_editor); +} + +OpenXREditorPlugin::~OpenXREditorPlugin() { +} diff --git a/modules/openxr/editor/openxr_editor_plugin.h b/modules/openxr/editor/openxr_editor_plugin.h new file mode 100644 index 0000000000..af8ee7d54c --- /dev/null +++ b/modules/openxr/editor/openxr_editor_plugin.h @@ -0,0 +1,53 @@ +/*************************************************************************/ +/* openxr_editor_plugin.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_EDITOR_PLUGIN_H +#define OPENXR_EDITOR_PLUGIN_H + +#include "editor/editor_plugin.h" +#include "openxr_action_map_editor.h" + +class OpenXREditorPlugin : public EditorPlugin { + GDCLASS(OpenXREditorPlugin, EditorPlugin); + + OpenXRActionMapEditor *action_map_editor = nullptr; + +public: + virtual String get_name() const override { return "OpenXRPlugin"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_node) override; + virtual bool handles(Object *p_node) const override; + virtual void make_visible(bool p_visible) override; + + OpenXREditorPlugin(); + ~OpenXREditorPlugin(); +}; + +#endif // !OPENXR_EDITOR_PLUGIN_H diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp new file mode 100644 index 0000000000..24ac5494dd --- /dev/null +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -0,0 +1,274 @@ +/*************************************************************************/ +/* openxr_interaction_profile_editor.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_editor.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/text_edit.h" + +/////////////////////////////////////////////////////////////////////////// +// Interaction profile editor base + +void OpenXRInteractionProfileEditorBase::_bind_methods() { + ClassDB::bind_method(D_METHOD("_add_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_add_binding); + ClassDB::bind_method(D_METHOD("_remove_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_remove_binding); + ClassDB::bind_method(D_METHOD("_update_interaction_profile"), &OpenXRInteractionProfileEditorBase::_update_interaction_profile); +} + +void OpenXRInteractionProfileEditorBase::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _update_interaction_profile(); + } break; + + case NOTIFICATION_THEME_CHANGED: { + _theme_changed(); + } break; + } +} + +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()); + + Ref<OpenXRAction> action = action_map->get_action(p_action); + ERR_FAIL_COND(action.is_null()); + + Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action); + if (binding.is_null()) { + // create a new binding + binding.instantiate(); + binding->set_action(action); + interaction_profile->add_binding(binding); + } + + binding->add_path(p_path); + + // Update our toplevel paths + action->set_toplevel_paths(action_map->get_top_level_paths(action)); + + call_deferred("_update_interaction_profile"); +} + +void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, const String p_path) { + ERR_FAIL_COND(action_map.is_null()); + ERR_FAIL_COND(interaction_profile.is_null()); + + Ref<OpenXRAction> action = action_map->get_action(p_action); + ERR_FAIL_COND(action.is_null()); + + Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action); + if (binding.is_valid()) { + binding->remove_path(p_path); + + if (binding->get_path_count() == 0) { + interaction_profile->remove_binding(binding); + } + + // Update our toplevel paths + action->set_toplevel_paths(action_map->get_top_level_paths(action)); + + call_deferred("_update_interaction_profile"); + } +} + +OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) { + 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); + if (profile_def != nullptr) { + profile_name = profile_def->display_name; + } + + set_name(profile_name); + set_h_size_flags(SIZE_EXPAND_FILL); + set_v_size_flags(SIZE_EXPAND_FILL); +} + +/////////////////////////////////////////////////////////////////////////// +// Default interaction profile editor + +void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) { + selecting_for_io_path = p_io_path; + select_action_dialog->open(); +} + +void OpenXRInteractionProfileEditor::action_selected(const String p_action) { + _add_binding(p_action, selecting_for_io_path); + selecting_for_io_path = ""; +} + +void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRDefs::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); + + Label *path_label = memnew(Label); + path_label->set_text(p_io_path->display_name); + path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + path_hb->add_child(path_label); + + Label *type_label = memnew(Label); + switch (p_io_path->action_type) { + case OpenXRAction::OPENXR_ACTION_BOOL: { + type_label->set_text(TTR("Boolean")); + } break; + case OpenXRAction::OPENXR_ACTION_FLOAT: { + type_label->set_text(TTR("Float")); + } break; + case OpenXRAction::OPENXR_ACTION_VECTOR2: { + type_label->set_text(TTR("Vector2")); + } break; + case OpenXRAction::OPENXR_ACTION_POSE: { + type_label->set_text(TTR("Pose")); + } break; + case OpenXRAction::OPENXR_ACTION_HAPTIC: { + type_label->set_text(TTR("Haptic")); + } break; + default: { + type_label->set_text(TTR("Unknown")); + } break; + } + type_label->set_custom_minimum_size(Size2(50.0, 0.0)); + path_hb->add_child(type_label); + + Button *path_add = memnew(Button); + path_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + path_add->set_flat(true); + Vector<Variant> add_binds; + add_binds.push_back(String(p_io_path->openxr_path)); + path_add->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for), add_binds); + path_hb->add_child(path_add); + + if (interaction_profile.is_valid()) { + String io_path = String(p_io_path->openxr_path); + Array bindings = interaction_profile->get_bindings(); + for (int i = 0; i < bindings.size(); i++) { + Ref<OpenXRIPBinding> binding = bindings[i]; + if (binding->has_path(io_path)) { + Ref<OpenXRAction> action = binding->get_action(); + + HBoxContainer *action_hb = memnew(HBoxContainer); + action_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + p_container->add_child(action_hb); + + Control *indent_node = memnew(Control); + indent_node->set_custom_minimum_size(Size2(10.0, 0.0)); + action_hb->add_child(indent_node); + + Label *action_label = memnew(Label); + action_label->set_text(action->get_name_with_set() + ": " + action->get_localized_name()); + action_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + action_hb->add_child(action_label); + + Button *action_rem = memnew(Button); + action_rem->set_flat(true); + action_rem->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); + Vector<Variant> remove_binds; + remove_binds.push_back(action->get_name_with_set()); + remove_binds.push_back(String(p_io_path->openxr_path)); + action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditorBase *)this, &OpenXRInteractionProfileEditorBase::_remove_binding), remove_binds); + action_hb->add_child(action_rem); + } + } + } +} + +void OpenXRInteractionProfileEditor::_update_interaction_profile() { + ERR_FAIL_NULL(profile_def); + + // out with the old... + while (main_hb->get_child_count() > 0) { + memdelete(main_hb->get_child(0)); + } + + // 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]; + + if (!top_level_paths.has(io_path->top_level_path)) { + top_level_paths.push_back(io_path->top_level_path); + } + } + + for (int i = 0; i < top_level_paths.size(); i++) { + PanelContainer *panel = memnew(PanelContainer); + panel->set_v_size_flags(Control::SIZE_EXPAND_FILL); + main_hb->add_child(panel); + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + + VBoxContainer *container = memnew(VBoxContainer); + panel->add_child(container); + + Label *label = memnew(Label); + label->set_text(top_level_paths[i]->display_name); + 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]; + if (io_path->top_level_path == top_level_paths[i]) { + _add_io_path(container, io_path); + } + } + } +} + +void OpenXRInteractionProfileEditor::_theme_changed() { + for (int i = 0; i < main_hb->get_child_count(); i++) { + Control *panel = static_cast<Control *>(main_hb->get_child(i)); + if (panel) { + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + } + } +} + +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 new file mode 100644 index 0000000000..f50da1a003 --- /dev/null +++ b/modules/openxr/editor/openxr_interaction_profile_editor.h @@ -0,0 +1,83 @@ +/*************************************************************************/ +/* openxr_interaction_profile_editor.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_EDITOR_H +#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 "scene/gui/scroll_container.h" + +#include "openxr_select_action_dialog.h" + +class OpenXRInteractionProfileEditorBase : public ScrollContainer { + GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer); + +protected: + Ref<OpenXRInteractionProfile> interaction_profile; + Ref<OpenXRActionMap> action_map; + + static void _bind_methods(); + void _notification(int p_what); + + const OpenXRDefs::InteractionProfile *profile_def = nullptr; + +public: + Ref<OpenXRInteractionProfile> get_interaction_profile() { return interaction_profile; } + + virtual void _update_interaction_profile() {} + virtual void _theme_changed() {} + void _add_binding(const String p_action, const String p_path); + void _remove_binding(const String p_action, const String p_path); + + OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile); +}; + +class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase { + GDCLASS(OpenXRInteractionProfileEditor, OpenXRInteractionProfileEditorBase); + +private: + String selecting_for_io_path; + HBoxContainer *main_hb = nullptr; + OpenXRSelectActionDialog *select_action_dialog = nullptr; + + void _add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path); + +public: + void select_action_for(const String p_io_path); + void action_selected(const String p_action); + + virtual void _update_interaction_profile() override; + virtual void _theme_changed() override; + OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile); +}; + +#endif // !OPENXR_INTERACTION_PROFILE_EDITOR_H diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp new file mode 100644 index 0000000000..c2a2965200 --- /dev/null +++ b/modules/openxr/editor/openxr_select_action_dialog.cpp @@ -0,0 +1,135 @@ +/*************************************************************************/ +/* openxr_select_action_dialog.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_select_action_dialog.h" +#include "editor/editor_node.h" + +void OpenXRSelectActionDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("action_selected", PropertyInfo(Variant::STRING, "action"))); +} + +void OpenXRSelectActionDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + } break; + } +} + +void OpenXRSelectActionDialog::_on_select_action(const String p_action) { + if (selected_action != "") { + NodePath button_path = action_buttons[selected_action]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(true); + } + } + + selected_action = p_action; + + if (selected_action != "") { + NodePath button_path = action_buttons[selected_action]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(false); + } + } +} + +void OpenXRSelectActionDialog::open() { + ERR_FAIL_COND(action_map.is_null()); + + // out with the old... + while (main_vb->get_child_count() > 0) { + memdelete(main_vb->get_child(0)); + } + + selected_action = ""; + action_buttons.clear(); + + Array action_sets = action_map->get_action_sets(); + for (int i = 0; i < action_sets.size(); i++) { + Ref<OpenXRActionSet> action_set = action_sets[i]; + + Label *action_set_label = memnew(Label); + action_set_label->set_text(action_set->get_localized_name()); + main_vb->add_child(action_set_label); + + Array actions = action_set->get_actions(); + for (int j = 0; j < actions.size(); j++) { + Ref<OpenXRAction> action = actions[j]; + + HBoxContainer *action_hb = memnew(HBoxContainer); + main_vb->add_child(action_hb); + + Control *indent_node = memnew(Control); + indent_node->set_custom_minimum_size(Size2(10.0, 0.0)); + action_hb->add_child(indent_node); + + Button *action_button = memnew(Button); + String action_name = action->get_name_with_set(); + Vector<Variant> binds; + binds.push_back(action_name); + action_button->set_flat(true); + action_button->set_text(action->get_name() + ": " + action->get_localized_name()); + action_button->connect("pressed", callable_mp(this, &OpenXRSelectActionDialog::_on_select_action), binds); + action_hb->add_child(action_button); + + action_buttons[action_name] = action_button->get_path(); + } + } + + popup_centered(); +} + +void OpenXRSelectActionDialog::ok_pressed() { + if (selected_action == "") { + return; + } + + emit_signal("action_selected", selected_action); + + hide(); +} + +OpenXRSelectActionDialog::OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map) { + action_map = p_action_map; + + set_title(TTR("Select an action")); + + scroll = memnew(ScrollContainer); + scroll->set_custom_minimum_size(Size2(600.0, 400.0)); + add_child(scroll); + + main_vb = memnew(VBoxContainer); + main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + scroll->add_child(main_vb); +} diff --git a/modules/openxr/editor/openxr_select_action_dialog.h b/modules/openxr/editor/openxr_select_action_dialog.h new file mode 100644 index 0000000000..ea2c30373b --- /dev/null +++ b/modules/openxr/editor/openxr_select_action_dialog.h @@ -0,0 +1,67 @@ +/*************************************************************************/ +/* openxr_select_action_dialog.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_SELECT_ACTION_DIALOG_H +#define OPENXR_SELECT_ACTION_DIALOG_H + +#include "../action_map/openxr_action_map.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/label.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/text_edit.h" + +class OpenXRSelectActionDialog : public ConfirmationDialog { + GDCLASS(OpenXRSelectActionDialog, ConfirmationDialog); + +private: + Ref<OpenXRActionMap> action_map; + String selected_action; + Dictionary action_buttons; + + VBoxContainer *main_vb = nullptr; + ScrollContainer *scroll = nullptr; + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + void _on_select_action(const String p_action); + void open(); + virtual void ok_pressed() override; + + OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map); +}; + +#endif // !OPENXR_SELECT_ACTION_DIALOG_H diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp new file mode 100644 index 0000000000..12b110f146 --- /dev/null +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp @@ -0,0 +1,125 @@ +/*************************************************************************/ +/* openxr_select_interaction_profile_dialog.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_select_interaction_profile_dialog.h" + +void OpenXRSelectInteractionProfileDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("interaction_profile_selected", PropertyInfo(Variant::STRING, "interaction_profile"))); +} + +void OpenXRSelectInteractionProfileDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); + } break; + } +} + +void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const String p_interaction_profile) { + if (selected_interaction_profile != "") { + NodePath button_path = ip_buttons[selected_interaction_profile]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(true); + } + } + + selected_interaction_profile = p_interaction_profile; + + if (selected_interaction_profile != "") { + NodePath button_path = ip_buttons[selected_interaction_profile]; + Button *button = static_cast<Button *>(get_node(button_path)); + if (button != nullptr) { + button->set_flat(false); + } + } +} + +void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) { + int available_count = 0; + + // out with the old... + while (main_vb->get_child_count() > 0) { + memdelete(main_vb->get_child(0)); + } + + selected_interaction_profile = ""; + ip_buttons.clear(); + + // in with the new + PackedStringArray interaction_profiles = OpenXRDefs::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); + Vector<Variant> binds; + binds.push_back(path); + ip_button->set_flat(true); + ip_button->set_text(OpenXRDefs::get_profile(path)->display_name); + ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile), binds); + main_vb->add_child(ip_button); + + ip_buttons[path] = ip_button->get_path(); + available_count++; + } + } + + if (available_count == 0) { + // give warning that we have all profiles selected + + } else { + // TODO maybe if we only have one, auto select it? + + popup_centered(); + } +} + +void OpenXRSelectInteractionProfileDialog::ok_pressed() { + if (selected_interaction_profile == "") { + return; + } + + emit_signal("interaction_profile_selected", selected_interaction_profile); + + hide(); +} + +OpenXRSelectInteractionProfileDialog::OpenXRSelectInteractionProfileDialog() { + set_title("Select an interaction profile"); + + scroll = memnew(ScrollContainer); + scroll->set_custom_minimum_size(Size2(600.0, 400.0)); + add_child(scroll); + + main_vb = memnew(VBoxContainer); + // main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + scroll->add_child(main_vb); +} diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h new file mode 100644 index 0000000000..d177861ff3 --- /dev/null +++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* openxr_select_interaction_profile_dialog.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_SELECT_INTERACTION_PROFILE_DIALOG_H +#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H + +#include "../action_map/openxr_defs.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/label.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/text_edit.h" + +class OpenXRSelectInteractionProfileDialog : public ConfirmationDialog { + GDCLASS(OpenXRSelectInteractionProfileDialog, ConfirmationDialog); + +private: + String selected_interaction_profile; + Dictionary ip_buttons; + + VBoxContainer *main_vb = nullptr; + ScrollContainer *scroll = nullptr; + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + void _on_select_interaction_profile(const String p_interaction_profile); + void open(PackedStringArray p_do_not_include); + virtual void ok_pressed() override; + + OpenXRSelectInteractionProfileDialog(); +}; + +#endif // !OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 5242ee6063..f3064041b8 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -40,10 +40,11 @@ #include <openxr/openxr.h> class OpenXRAPI; +class OpenXRActionMap; class OpenXRExtensionWrapper { protected: - OpenXRAPI *openxr_api; + OpenXRAPI *openxr_api = nullptr; // Store extension we require. // If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp index c7c840fdf3..8736296f7a 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -30,9 +30,9 @@ #include "core/string/print_string.h" -#include "modules/openxr/extensions/openxr_vulkan_extension.h" -#include "modules/openxr/openxr_api.h" -#include "modules/openxr/openxr_util.h" +#include "../extensions/openxr_vulkan_extension.h" +#include "../openxr_api.h" +#include "../openxr_util.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/rendering_server_globals.h" #include "servers/rendering_server.h" diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 7752878d82..ae3617938e 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -48,14 +48,14 @@ #include "extensions/openxr_vulkan_extension.h" #endif -#include "modules/openxr/openxr_interface.h" +#include "openxr_interface.h" OpenXRAPI *OpenXRAPI::singleton = nullptr; -bool OpenXRAPI::openxr_is_enabled() { +bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled" - if (Engine::get_singleton()->is_editor_hint()) { + if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) { #ifdef TOOLS_ENABLED // Disabled for now, using XR inside of the editor we'll be working on during the coming months. return false; @@ -172,11 +172,18 @@ bool OpenXRAPI::load_supported_extensions() { bool OpenXRAPI::is_extension_supported(const char *p_extension) const { for (uint32_t i = 0; i < num_supported_extensions; i++) { - if (strcmp(supported_extensions[i].extensionName, p_extension)) { + if (strcmp(supported_extensions[i].extensionName, p_extension) == 0) { +#ifdef DEBUG + print_line("OpenXR: requested extension", p_extension, "is supported"); +#endif return true; } } +#ifdef DEBUG + print_line("OpenXR: requested extension", p_extension, "is not supported"); +#endif + return false; } @@ -207,6 +214,14 @@ bool OpenXRAPI::create_instance() { } } + // Add optional extensions for controllers that may be supported. + // Overkill to create extension classes for this. + requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available; + requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available; + requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available; + requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available; + requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available; + // Check which extensions are supported enabled_extensions.clear(); for (auto &requested_extension : requested_extensions) { @@ -408,7 +423,7 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType for (uint32_t i = 0; i < view_count; i++) { view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW; - view_configuration_views[i].next = NULL; + view_configuration_views[i].next = nullptr; } result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views); @@ -680,10 +695,10 @@ bool OpenXRAPI::create_main_swapchain() { for (uint32_t i = 0; i < view_count; i++) { views[i].type = XR_TYPE_VIEW; - views[i].next = NULL; + views[i].next = nullptr; projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; - projection_views[i].next = NULL; + projection_views[i].next = nullptr; projection_views[i].subImage.swapchain = swapchain; projection_views[i].subImage.imageArrayIndex = i; projection_views[i].subImage.imageRect.offset.x = 0; @@ -1147,7 +1162,7 @@ bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) { } // we don't have valid view info - if (views == NULL || !view_pose_valid) { + if (views == nullptr || !view_pose_valid) { return false; } @@ -1167,7 +1182,7 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z } // we don't have valid view info - if (views == NULL || !view_pose_valid) { + if (views == nullptr || !view_pose_valid) { return false; } diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 1a1508e993..7baf581a05 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -75,6 +75,12 @@ private: Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; Vector<const char *> enabled_extensions; + bool ext_hp_mixed_reality_available = false; + bool ext_samsung_odyssey_available = false; + bool ext_vive_cosmos_available = false; + bool ext_vive_focus3_available = false; + bool ext_huawei_controller_available = false; + // composition layer providers Vector<OpenXRCompositionLayerProvider *> composition_layer_providers; @@ -222,7 +228,7 @@ protected: void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity); public: - static bool openxr_is_enabled(); + static bool openxr_is_enabled(bool p_check_run_in_editor = true); static OpenXRAPI *get_singleton(); String get_error_string(XrResult result); diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 47ee1316e7..0b48be5f2a 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -38,6 +38,22 @@ #include "action_map/openxr_action_set.h" #include "action_map/openxr_interaction_profile.h" +#ifdef TOOLS_ENABLED + +#include "editor/editor_node.h" +#include "editor/openxr_editor_plugin.h" + +static void _editor_init() { + if (OpenXRAPI::openxr_is_enabled(false)) { + // Only add our OpenXR action map editor if OpenXR is enabled for our project + + OpenXREditorPlugin *openxr_plugin = memnew(OpenXREditorPlugin()); + EditorNode::get_singleton()->add_editor_plugin(openxr_plugin); + } +} + +#endif + OpenXRAPI *openxr_api = nullptr; Ref<OpenXRInterface> openxr_interface; @@ -74,6 +90,10 @@ void register_openxr_types() { openxr_interface->initialize(); } } + +#ifdef TOOLS_ENABLED + EditorNode::add_init_callback(_editor_init); +#endif } void unregister_openxr_types() { diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h index a22e52dd17..8453c5341d 100644 --- a/modules/raycast/raycast_occlusion_cull.h +++ b/modules/raycast/raycast_occlusion_cull.h @@ -115,7 +115,7 @@ private: struct Scenario { struct RaycastThreadData { - CameraRayTile *rays; + CameraRayTile *rays = nullptr; const uint32_t *masks; }; @@ -124,7 +124,7 @@ private: uint32_t vertex_count; Transform3D xform; const Vector3 *read; - Vector3 *write; + Vector3 *write = nullptr; }; Thread *commit_thread = nullptr; diff --git a/modules/regex/regex.h b/modules/regex/regex.h index a745c50a58..e7221f4070 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -71,7 +71,7 @@ public: class RegEx : public RefCounted { GDCLASS(RegEx, RefCounted); - void *general_ctx; + void *general_ctx = nullptr; void *code = nullptr; String pattern; diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 79ef2de929..7fe2e589b1 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -136,7 +136,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const p_extensions->push_back("svg"); } -Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) { +Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) { String svg = p_fileaccess->get_as_utf8_string(); create_image_from_string(p_image, svg, p_scale, false, false); ERR_FAIL_COND_V(p_image->is_empty(), FAILED); diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index d0bd71d92d..94c17fda43 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -42,7 +42,7 @@ public: void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; } void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color); - virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) override; + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override; virtual void get_recognized_extensions(List<String> *p_extensions) const override; }; diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index 06e934c67d..3331254b20 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -51,7 +51,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length } int paren_size = PAREN_STACK_DEPTH; - ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry)); + ParenStackEntry *paren_stack = static_cast<ParenStackEntry *>(memalloc(paren_size * sizeof(ParenStackEntry))); int script_start; int script_end = p_start; @@ -77,7 +77,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length if (unlikely(paren_sp >= paren_size)) { // If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text. paren_size += PAREN_STACK_DEPTH; - paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry)); + paren_stack = static_cast<ParenStackEntry *>(memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry))); } paren_stack[paren_sp].pair_index = ch; paren_stack[paren_sp].script_code = script_code; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index e02ddbb3f4..4cd5dada4d 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -89,12 +89,12 @@ TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerA } void TextServerAdvanced::_bmp_font_destroy(void *p_data) { - bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data); + bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data); memdelete(bm_font); } hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -114,7 +114,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_ } hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -128,7 +128,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, vo } hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -142,7 +142,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, vo } hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -156,7 +156,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, vo } hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -173,7 +173,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p } hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -192,7 +192,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_ } hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) { - const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); + const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -410,7 +410,6 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { } uint64_t len = f->get_length(); PackedByteArray icu_data = f->get_buffer(len); - f->close(); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -461,9 +460,8 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { icu_data.resize(U_ICUDATA_SIZE); memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); f->store_buffer(icu_data); - f->close(); - return true; + return true; #else return false; #endif @@ -768,12 +766,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ for (int i = 0; i < p_data->textures.size(); i++) { const FontTexture &ct = p_data->textures[i]; - if (RenderingServer::get_singleton() != nullptr) { - if (ct.texture->get_format() != p_image_format) { - continue; - } - } - if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. continue; } @@ -815,12 +807,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ ret.y = 0; int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); - if (mw > texsize) { - texsize = mw; // Special case, adapt to it? - } - if (mh > texsize) { - texsize = mh; // Special case, adapt to it? - } #ifdef GDEXTENSION texsize = Math::next_power_of_2(texsize); @@ -832,6 +818,20 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ } else { texsize = MIN(texsize, 1024); } + if (mw > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mw); +#else + texsize = next_power_of_2(mw); +#endif + } + if (mh > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mh); +#else + texsize = next_power_of_2(mh); +#endif + } FontTexture tex; tex.texture_w = texsize; @@ -908,7 +908,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) { } static int ft_move_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); if (!(context->contour && context->contour->edges.empty())) { context->contour = &context->shape->addContour(); } @@ -917,7 +917,7 @@ static int ft_move_to(const FT_Vector *to, void *user) { } static int ft_line_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); msdfgen::Point2 endpoint = ft_point2(*to); if (endpoint != context->position) { context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint)); @@ -927,21 +927,21 @@ static int ft_line_to(const FT_Vector *to, void *user) { } static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to))); context->position = ft_point2(*to); return 0; } static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to))); context->position = ft_point2(*to); return 0; } void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const { - MSDFThreadData *td = (MSDFThreadData *)p_td; + MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td); msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape); int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y; @@ -997,8 +997,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( int mw = w + p_rect_margin * 2; int mh = h + p_rect_margin * 2; - ERR_FAIL_COND_V(mw > 1024, FontGlyph()); - ERR_FAIL_COND_V(mh > 1024, FontGlyph()); + ERR_FAIL_COND_V(mw > 4096, FontGlyph()); + ERR_FAIL_COND_V(mh > 4096, FontGlyph()); FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); @@ -1039,20 +1039,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata); - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. int32_t *offw = tex.offsets.ptrw(); @@ -1078,8 +1065,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma int mw = w + p_rect_margin * 2; int mh = h + p_rect_margin * 2; - ERR_FAIL_COND_V(mw > 1024, FontGlyph()); - ERR_FAIL_COND_V(mh > 1024, FontGlyph()); + ERR_FAIL_COND_V(mw > 4096, FontGlyph()); + ERR_FAIL_COND_V(mh > 4096, FontGlyph()); int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; @@ -1124,21 +1111,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata); - - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. int32_t *offw = tex.offsets.ptrw(); @@ -1885,9 +1858,7 @@ void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->fixed_size != p_fixed_size) { - fd->fixed_size = p_fixed_size; - } + fd->fixed_size = p_fixed_size; } int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const { @@ -1941,9 +1912,7 @@ void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, Te ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->subpixel_positioning != p_subpixel) { - fd->subpixel_positioning = p_subpixel; - } + fd->subpixel_positioning = p_subpixel; } TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(const RID &p_font_rid) const { @@ -2306,11 +2275,12 @@ void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vec Ref<Image> img; img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); tex.texture = Ref<ImageTexture>(); tex.texture.instantiate(); tex.texture->create_from_image(img); + tex.dirty = false; } Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { @@ -2325,7 +2295,7 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, con const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; Ref<Image> img; img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); return img; } @@ -2598,10 +2568,10 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); +#ifdef MODULE_FREETYPE_ENABLED PackedVector3Array points; PackedInt32Array contours; - bool orientation; -#ifdef MODULE_FREETYPE_ENABLED + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); @@ -2618,16 +2588,16 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); } - orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); -#else - return Dictionary(); -#endif + bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); Dictionary out; out["points"] = points; out["contours"] = contours; out["orientation"] = orientation; return out; +#else + return Dictionary(); +#endif } Array TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { @@ -2890,6 +2860,19 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; @@ -2953,6 +2936,19 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; @@ -3876,9 +3872,9 @@ double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double } } } - double adv_remain = 0; if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) { double delta_width_per_space = (p_width - justification_width) / space_count; + double adv_remain = 0; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { @@ -4638,6 +4634,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star } RID f = p_fonts[p_fb_index]; + FontDataAdvanced *fd = font_owner.get_or_null(f); + Vector2i fss = _get_size(fd, fs); hb_font_t *hb_font = _font_get_hb_handle(f, fs); double scale = font_get_scale(f, fs); double sp_sp = font_get_spacing(f, fs, SPACING_SPACE); @@ -4719,6 +4717,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star gl.index = glyph_info[i].codepoint; if (gl.index != 0) { + _ensure_glyph(fd, fss, gl.index); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { if (subpos) { gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea; diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index bb3968ee3f..8afba6adca 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -159,6 +159,7 @@ class TextServerAdvanced : public TextServerExtension { int texture_h = 0; PackedInt32Array offsets; Ref<ImageTexture> texture; + bool dirty = true; }; struct FontTexturePosition { diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 6c2e5a6084..47c6a73b24 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -209,12 +209,6 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ for (int i = 0; i < p_data->textures.size(); i++) { const FontTexture &ct = p_data->textures[i]; - if (RenderingServer::get_singleton() != nullptr) { - if (ct.texture->get_format() != p_image_format) { - continue; - } - } - if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. continue; } @@ -256,12 +250,6 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ ret.y = 0; int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); - if (mw > texsize) { - texsize = mw; // Special case, adapt to it? - } - if (mh > texsize) { - texsize = mh; // Special case, adapt to it? - } #ifdef GDEXTENSION texsize = Math::next_power_of_2(texsize); @@ -274,6 +262,20 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ } else { texsize = MIN(texsize, 1024); } + if (mw > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mw); +#else + texsize = next_power_of_2(mw); +#endif + } + if (mh > texsize) { // Special case, adapt to it? +#ifdef GDEXTENSION + texsize = Math::next_power_of_2(mh); +#else + texsize = next_power_of_2(mh); +#endif + } FontTexture tex; tex.texture_w = texsize; @@ -350,7 +352,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) { } static int ft_move_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); if (!(context->contour && context->contour->edges.empty())) { context->contour = &context->shape->addContour(); } @@ -359,7 +361,7 @@ static int ft_move_to(const FT_Vector *to, void *user) { } static int ft_line_to(const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); msdfgen::Point2 endpoint = ft_point2(*to); if (endpoint != context->position) { context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint)); @@ -369,21 +371,21 @@ static int ft_line_to(const FT_Vector *to, void *user) { } static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to))); context->position = ft_point2(*to); return 0; } static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { - MSContext *context = reinterpret_cast<MSContext *>(user); + MSContext *context = static_cast<MSContext *>(user); context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to))); context->position = ft_point2(*to); return 0; } void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const { - MSDFThreadData *td = (MSDFThreadData *)p_td; + MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td); msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape); int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y; @@ -439,8 +441,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( int mw = w + p_rect_margin * 2; int mh = h + p_rect_margin * 2; - ERR_FAIL_COND_V(mw > 1024, FontGlyph()); - ERR_FAIL_COND_V(mh > 1024, FontGlyph()); + ERR_FAIL_COND_V(mw > 4096, FontGlyph()); + ERR_FAIL_COND_V(mh > 4096, FontGlyph()); FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); @@ -481,20 +483,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata); - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. int32_t *offw = tex.offsets.ptrw(); @@ -520,8 +509,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma int mw = w + p_rect_margin * 2; int mh = h + p_rect_margin * 2; - ERR_FAIL_COND_V(mw > 1024, FontGlyph()); - ERR_FAIL_COND_V(mh > 1024, FontGlyph()); + ERR_FAIL_COND_V(mw > 4096, FontGlyph()); + ERR_FAIL_COND_V(mh > 4096, FontGlyph()); int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; @@ -566,21 +555,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma } } - // Blit to image and texture. - { - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata); - - if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); - } - } - } + tex.dirty = true; // Update height array. int32_t *offw = tex.offsets.ptrw(); @@ -1046,9 +1021,7 @@ void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->fixed_size != p_fixed_size) { - fd->fixed_size = p_fixed_size; - } + fd->fixed_size = p_fixed_size; } int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const { @@ -1102,9 +1075,7 @@ void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, Te ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - if (fd->subpixel_positioning != p_subpixel) { - fd->subpixel_positioning = p_subpixel; - } + fd->subpixel_positioning = p_subpixel; } TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(const RID &p_font_rid) const { @@ -1467,11 +1438,12 @@ void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vec Ref<Image> img; img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); tex.texture = Ref<ImageTexture>(); tex.texture.instantiate(); tex.texture->create_from_image(img); + tex.dirty = false; } Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { @@ -1486,7 +1458,7 @@ Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, con const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; Ref<Image> img; img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); return img; } @@ -1745,10 +1717,10 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); +#ifdef MODULE_FREETYPE_ENABLED PackedVector3Array points; PackedInt32Array contours; - bool orientation; -#ifdef MODULE_FREETYPE_ENABLED + int32_t index = p_index & 0xffffff; // Remove subpixel shifts. int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); @@ -1765,16 +1737,16 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); } - orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); -#else - return Dictionary(); -#endif + bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); Dictionary out; out["points"] = points; out["contours"] = contours; out["orientation"] = orientation; return out; +#else + return Dictionary(); +#endif } Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { @@ -2019,6 +1991,19 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; @@ -2082,6 +2067,19 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI } #endif if (RenderingServer::get_singleton() != nullptr) { + if (fd->cache[size]->textures[gl.texture_idx].dirty) { + FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img; + img.instantiate(); + img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + if (tex.texture.is_null()) { + tex.texture.instantiate(); + tex.texture->create_from_image(img); + } else { + tex.texture->update(img); + } + tex.dirty = false; + } RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 3944c371b7..ea77659b5d 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -127,6 +127,7 @@ class TextServerFallback : public TextServerExtension { int texture_h = 0; PackedInt32Array offsets; Ref<ImageTexture> texture; + bool dirty = true; }; struct FontTexturePosition { @@ -343,8 +344,12 @@ public: virtual bool has(const RID &p_rid) override; virtual bool load_support_data(const String &p_filename) override; - virtual String get_support_data_filename() const override { return ""; }; - virtual String get_support_data_info() const override { return "Not supported"; }; + virtual String get_support_data_filename() const override { + return ""; + }; + virtual String get_support_data_info() const override { + return "Not supported"; + }; virtual bool save_support_data(const String &p_filename) const override; virtual bool is_locale_right_to_left(const String &p_locale) const override; diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 5060c1ab35..08ad1ef9f8 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff return OK; } -Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -330,7 +330,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force } } - f->close(); return err; } @@ -339,12 +338,14 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const } static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) { - FileAccessMemory memfile; - Error open_memfile_error = memfile.open_custom(p_tga, p_size); + Ref<FileAccessMemory> memfile; + memfile.instantiate(); + Error open_memfile_error = memfile->open_custom(p_tga, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer."); + Ref<Image> img; img.instantiate(); - Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f); + Error load_error = ImageLoaderTGA().load_image(img, memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load TGA image."); return img; } diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index 282a2a1662..9b7cbbac77 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader { static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size); public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTGA(); }; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 0a4ad96d97..3f5140cc8c 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -114,7 +114,7 @@ void VideoStreamPlaybackTheora::video_write() { } void VideoStreamPlaybackTheora::clear() { - if (!file) { + if (file.is_null()) { return; } @@ -152,10 +152,7 @@ void VideoStreamPlaybackTheora::clear() { theora_eos = false; vorbis_eos = false; - if (file) { - memdelete(file); - } - file = nullptr; + file.unref(); playing = false; }; @@ -165,11 +162,8 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { th_setup_info *ts = nullptr; file_name = p_file; - if (file) { - memdelete(file); - } file = FileAccess::open(p_file, FileAccess::READ); - ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_file + "'."); + ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_file + "'."); #ifdef THEORA_USE_THREAD_STREAMING thread_exit = false; @@ -375,7 +369,7 @@ Ref<Texture2D> VideoStreamPlaybackTheora::get_texture() const { } void VideoStreamPlaybackTheora::update(float p_delta) { - if (!file) { + if (file.is_null()) { return; } @@ -506,9 +500,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } #ifdef THEORA_USE_THREAD_STREAMING - if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) { + if (file.is_valid() && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) { #else - if (file && /*!videobuf_ready && */ no_theora && theora_eos) { + if (file.is_valid() && /*!videobuf_ready && */ no_theora && theora_eos) { #endif //printf("video done, stopping\n"); stop(); @@ -627,7 +621,7 @@ int VideoStreamPlaybackTheora::get_mix_rate() const { #ifdef THEORA_USE_THREAD_STREAMING void VideoStreamPlaybackTheora::_streaming_thread(void *ud) { - VideoStreamPlaybackTheora *vs = (VideoStreamPlaybackTheora *)ud; + VideoStreamPlaybackTheora *vs = static_cast<VideoStreamPlaybackTheora *>(ud); while (!vs->thread_exit) { //just fill back the buffer @@ -664,10 +658,6 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() { memdelete(thread_sem); #endif clear(); - - if (file) { - memdelete(file); - } }; void VideoStreamTheora::_bind_methods() { @@ -680,8 +670,8 @@ void VideoStreamTheora::_bind_methods() { //////////// RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { if (r_error) { *r_error = ERR_CANT_OPEN; } @@ -697,8 +687,6 @@ RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_origi *r_error = OK; } - f->close(); - memdelete(f); return ogv_stream; } diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 3bc96908a2..6fa7313fad 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -56,7 +56,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { Image::Format format = Image::Format::FORMAT_L8; Vector<uint8_t> frame_data; int frames_pending = 0; - FileAccess *file = nullptr; + Ref<FileAccess> file; String file_name; int audio_frames_wrote = 0; Point2i size; @@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { RingBuffer<uint8_t> ring_buffer; Vector<uint8_t> read_buffer; bool thread_eof = false; - Semaphore *thread_sem; + Semaphore *thread_sem = nullptr; Thread thread; SafeFlag thread_exit; diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 688707a42d..1ff2600839 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -37,7 +37,7 @@ #include "thirdparty/tinyexr/tinyexr.h" -Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -47,8 +47,6 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f f->get_buffer(&w[0], src_image_len); - f->close(); - // Re-implementation of tinyexr's LoadEXRFromMemory using Godot types to store the Image data // and Godot's error codes. // When debugging after updating the thirdparty library, check that we're still in sync with diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h index aba5fdb959..c147861c26 100644 --- a/modules/tinyexr/image_loader_tinyexr.h +++ b/modules/tinyexr/image_loader_tinyexr.h @@ -35,7 +35,7 @@ class ImageLoaderTinyEXR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTinyEXR(); }; diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp index 3750994663..5fa6ace827 100644 --- a/modules/tinyexr/image_saver_tinyexr.cpp +++ b/modules/tinyexr/image_saver_tinyexr.cpp @@ -275,8 +275,8 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) print_error(String("Saving EXR failed. Error: {0}").format(varray(err))); return ERR_FILE_CANT_WRITE; } else { - FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE); + Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE); ref->store_buffer(mem, bytes); free(mem); } diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h index 6b5112f1af..faf39a14e4 100644 --- a/modules/visual_script/editor/visual_script_property_selector.h +++ b/modules/visual_script/editor/visual_script_property_selector.h @@ -62,23 +62,23 @@ class VisualScriptPropertySelector : public ConfirmationDialog { SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED }; - LineEdit *search_box; + LineEdit *search_box = nullptr; - Button *case_sensitive_button; - Button *hierarchy_button; + Button *case_sensitive_button = nullptr; + Button *hierarchy_button = nullptr; - Button *search_visual_script_nodes; - Button *search_classes; - Button *search_operators; + Button *search_visual_script_nodes = nullptr; + Button *search_classes = nullptr; + Button *search_operators = nullptr; - Button *search_methods; - Button *search_signals; - Button *search_constants; - Button *search_properties; - Button *search_theme_items; + Button *search_methods = nullptr; + Button *search_signals = nullptr; + Button *search_constants = nullptr; + Button *search_properties = nullptr; + Button *search_theme_items = nullptr; - OptionButton *scope_combo; - Tree *results_tree; + OptionButton *scope_combo = nullptr; + Tree *results_tree = nullptr; class SearchRunner; Ref<SearchRunner> search_runner; @@ -94,7 +94,7 @@ class VisualScriptPropertySelector : public ConfirmationDialog { void _item_selected(); void _hide_requested(); - EditorHelpBit *help_bit; + EditorHelpBit *help_bit = nullptr; bool properties = false; bool visual_script_generic = false; @@ -104,9 +104,9 @@ class VisualScriptPropertySelector : public ConfirmationDialog { String base_type; String base_script; ObjectID script; - Object *instance; + Object *instance = nullptr; bool virtuals_only = false; - VBoxContainer *vbox; + VBoxContainer *vbox = nullptr; protected: void _notification(int p_what); @@ -159,9 +159,9 @@ class VisualScriptPropertySelector::SearchRunner : public RefCounted { } }; - VisualScriptPropertySelector *selector_ui; - Control *ui_service; - Tree *results_tree; + VisualScriptPropertySelector *selector_ui = nullptr; + Control *ui_service = nullptr; + Tree *results_tree = nullptr; String term; int search_flags; int scope_flags; diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index d72bdf9128..6b27af15f6 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -495,7 +495,7 @@ class VisualScriptLanguage : public ScriptLanguage { String _debug_error; int _debug_call_stack_pos = 0; int _debug_max_call_stack; - CallLevel *_call_stack; + CallLevel *_call_stack = nullptr; public: StringName notification = "_notification"; diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index f6bc855a50..7e2df23618 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -1185,11 +1185,11 @@ public: VisualScriptBuiltinFunc::BuiltinFunc func; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str); return 0; } diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index fef159bf87..bd36a9ceec 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -1302,7 +1302,7 @@ public: VisualScriptInstance *instance; VisualScriptExpression *expression; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //execute by parsing the tree directly virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) { switch (p_node->type) { @@ -1512,7 +1512,7 @@ public: return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!expression->root || expression->error_set) { r_error_str = expression->error_str; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index d28744a09f..7946d96b29 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -123,11 +123,11 @@ public: VisualScriptInstance *instance; bool with_value; - virtual int get_working_memory_size() const { return 1; } + virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (with_value) { *p_working_mem = *p_inputs[0]; return STEP_EXIT_FUNCTION_BIT; @@ -216,11 +216,11 @@ public: VisualScriptCondition *node; VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 1; } + //virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) { return 2; } else if (p_inputs[0]->operator bool()) { @@ -296,11 +296,11 @@ public: VisualScriptWhile *node; VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 1; } + //virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool keep_going = p_inputs[0]->operator bool(); if (keep_going) { @@ -379,11 +379,11 @@ public: VisualScriptIterator *node; VisualScriptInstance *instance; - virtual int get_working_memory_size() const { return 2; } + virtual int get_working_memory_size() const override { return 2; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_BEGIN_SEQUENCE) { p_working_mem[0] = *p_inputs[0]; bool valid; @@ -512,11 +512,11 @@ public: VisualScriptInstance *instance; int steps; - virtual int get_working_memory_size() const { return 1; } + virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_BEGIN_SEQUENCE) { p_working_mem[0] = 0; } @@ -599,11 +599,11 @@ public: VisualScriptInstance *instance; int case_count; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) { return case_count; //exit } @@ -778,11 +778,11 @@ public: StringName base_type; String script; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Object *obj = *p_inputs[0]; *p_outputs[0] = Variant(); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 2c9d23e457..5cc9236a9a 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -730,7 +730,7 @@ public: VisualScriptFunctionCall *node; VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } @@ -765,7 +765,7 @@ public: return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (call_mode) { case VisualScriptFunctionCall::CALL_MODE_SELF: { Object *object = instance->get_owner_ptr(); @@ -1468,7 +1468,7 @@ public: StringName index; bool needs_get; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } @@ -1529,7 +1529,7 @@ public: } } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (call_mode) { case VisualScriptPropertySet::CALL_MODE_SELF: { Object *object = instance->get_owner_ptr(); @@ -2155,7 +2155,7 @@ public: VisualScriptPropertyGet *node; VisualScriptInstance *instance; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (call_mode) { case VisualScriptPropertyGet::CALL_MODE_SELF: { Object *object = instance->get_owner_ptr(); @@ -2367,11 +2367,11 @@ public: int argcount; StringName name; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Object *obj = instance->get_owner_ptr(); obj->emit_signalp(name, p_inputs, argcount); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index b65b9f090a..6e10b72013 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -274,9 +274,9 @@ public: VisualScriptFunction *node; VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { int ac = node->get_argument_count(); for (int i = 0; i < ac; i++) { @@ -777,9 +777,9 @@ String VisualScriptComposeArray::get_text() const { class VisualScriptComposeArrayNode : public VisualScriptNodeInstance { public: int input_count = 0; - virtual int get_working_memory_size() const { return 0; } + virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (input_count > 0) { Array arr; for (int i = 0; i < input_count; i++) { @@ -1100,9 +1100,9 @@ public: bool unary; Variant::Operator op; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; if (unary) { Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid); @@ -1220,9 +1220,9 @@ void VisualScriptSelect::_bind_methods() { class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance { public: - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool cond = *p_inputs[0]; if (cond) { *p_outputs[0] = *p_inputs[1]; @@ -1332,7 +1332,7 @@ public: VisualScriptInstance *instance; StringName variable; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!instance->get_variable(variable, p_outputs[0])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("VariableGet not found in script: ") + "'" + String(variable) + "'"; @@ -1442,9 +1442,9 @@ public: VisualScriptInstance *instance; StringName variable; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!instance->set_variable(variable, *p_inputs[0])) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = RTR("VariableSet not found in script: ") + "'" + String(variable) + "'"; @@ -1561,9 +1561,9 @@ void VisualScriptConstant::_bind_methods() { class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { public: Variant constant; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = constant; return 0; } @@ -1654,9 +1654,9 @@ void VisualScriptPreload::_bind_methods() { class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance { public: Ref<Resource> preload; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = preload; return 0; } @@ -1713,9 +1713,9 @@ String VisualScriptIndexGet::get_caption() const { class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { public: - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; *p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid); @@ -1780,9 +1780,9 @@ String VisualScriptIndexSet::get_caption() const { class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { public: - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { bool valid; ((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid); @@ -1852,9 +1852,9 @@ int VisualScriptGlobalConstant::get_global_constant() { class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance { public: int index; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = CoreConstants::get_global_constant_value(index); return 0; } @@ -1965,9 +1965,9 @@ class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance { public: int value; bool valid; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Invalid constant name, pick a valid class constant."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2099,9 +2099,9 @@ class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstanc public: Variant value; bool valid; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Invalid constant name, pick a valid basic type constant."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2228,9 +2228,9 @@ VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_consta class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance { public: float value; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = value; return 0; } @@ -2322,9 +2322,9 @@ class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance public: Object *singleton; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = singleton; return 0; } @@ -2433,9 +2433,9 @@ public: VisualScriptInstance *instance; NodePath path; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); if (!node) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2613,9 +2613,9 @@ public: VisualScriptSceneTree *node; VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); if (!node) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -2709,9 +2709,9 @@ class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance { public: String path; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = path; return 0; } @@ -2781,9 +2781,9 @@ class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance { public: VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = instance->get_owner_ptr(); return 0; } @@ -2971,8 +2971,8 @@ public: int out_count; int work_mem_size; - virtual int get_working_memory_size() const { return work_mem_size; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int get_working_memory_size() const override { return work_mem_size; } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (GDVIRTUAL_IS_OVERRIDDEN_PTR(node, _step)) { Array in_values; Array out_values; @@ -3166,9 +3166,9 @@ public: int input_args; bool valid; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (!valid) { r_error_str = "Node requires a script with a _subcall(<args>) method to work."; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -3283,9 +3283,9 @@ class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance { public: VisualScriptInstance *instance; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { return 0; } }; @@ -3384,9 +3384,9 @@ public: Variant::Type type; int argcount; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Callable::CallError ce; Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce); if (ce.error != Callable::CallError::CALL_OK) { @@ -3500,8 +3500,8 @@ public: VisualScriptInstance *instance; StringName name; - virtual int get_working_memory_size() const { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int get_working_memory_size() const override { return 1; } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_outputs[0] = *p_working_mem; return 0; } @@ -3607,8 +3607,8 @@ public: VisualScriptInstance *instance; StringName name; - virtual int get_working_memory_size() const { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int get_working_memory_size() const override { return 1; } + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { *p_working_mem = *p_inputs[0]; *p_outputs[0] = *p_working_mem; return 0; @@ -3732,7 +3732,7 @@ public: StringName action; VisualScriptInputAction::Mode mode; - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { switch (mode) { case VisualScriptInputAction::MODE_PRESSED: { *p_outputs[0] = Input::get_singleton()->is_action_pressed(action); @@ -3909,9 +3909,9 @@ public: VisualScriptInstance *instance; Vector<StringName> outputs; - //virtual int get_working_memory_size() const { return 0; } + //virtual int get_working_memory_size() const override { return 0; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { Variant in = *p_inputs[0]; for (int i = 0; i < outputs.size(); i++) { diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index dcd8815394..e6e7f79d1f 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -95,11 +95,11 @@ public: VisualScriptYield::YieldMode mode; double wait_time; - virtual int get_working_memory_size() const { return 1; } //yield needs at least 1 + virtual int get_working_memory_size() const override { return 1; } //yield needs at least 1 //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_RESUME_YIELD) { return 0; //resuming yield } else { @@ -506,11 +506,11 @@ public: VisualScriptYieldSignal *node; VisualScriptInstance *instance; - virtual int get_working_memory_size() const { return 1; } + virtual int get_working_memory_size() const override { return 1; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) { + virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { if (p_start_mode == START_MODE_RESUME_YIELD) { return 0; //resuming yield } else { diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index d12e65a96a..03e145216a 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -78,9 +78,8 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); uint64_t len = f->get_length(); @@ -90,8 +89,6 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin f->get_buffer(w, len); - memdelete(f); - Ref<AudioStreamOGGVorbis> ogg_vorbis_stream; ogg_vorbis_stream.instantiate(); diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 902e182d83..0e41f6c973 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -211,7 +211,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { return img; } -Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderWEBP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -221,8 +221,6 @@ Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_forc f->get_buffer(&w[0], src_image_len); - f->close(); - Error err = webp_load_image_from_buffer(p_image.ptr(), w, src_image_len); return err; diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h index 327582ca55..1acd1459a0 100644 --- a/modules/webp/image_loader_webp.h +++ b/modules/webp/image_loader_webp.h @@ -35,7 +35,7 @@ class ImageLoaderWEBP : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderWEBP(); }; diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h index 3d0b365355..8fa5ea7779 100644 --- a/modules/webrtc/webrtc_peer_connection_js.h +++ b/modules/webrtc/webrtc_peer_connection_js.h @@ -63,16 +63,16 @@ private: static void _on_error(void *p_obj); public: - virtual ConnectionState get_connection_state() const; + virtual ConnectionState get_connection_state() const override; - virtual Error initialize(Dictionary configuration = Dictionary()); - virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary()); - virtual Error create_offer(); - virtual Error set_remote_description(String type, String sdp); - virtual Error set_local_description(String type, String sdp); - virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName); - virtual Error poll(); - virtual void close(); + virtual Error initialize(Dictionary configuration = Dictionary()) override; + virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary()) override; + virtual Error create_offer() override; + virtual Error set_remote_description(String type, String sdp) override; + virtual Error set_local_description(String type, String sdp) override; + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override; + virtual Error poll() override; + virtual void close() override; WebRTCPeerConnectionJS(); ~WebRTCPeerConnectionJS(); diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h index 61ea0002ea..ca327a56fa 100644 --- a/modules/websocket/emws_client.h +++ b/modules/websocket/emws_client.h @@ -53,15 +53,15 @@ private: static void _esws_on_close(void *obj, int code, const char *reason, int was_clean); public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()); - Ref<WebSocketPeer> get_peer(int p_peer_id) const; - void disconnect_from_host(int p_code = 1000, String p_reason = ""); - IPAddress get_connected_host() const; - uint16_t get_connected_port() const; - virtual ConnectionStatus get_connection_status() const; - int get_max_packet_size() const; - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override; + Ref<WebSocketPeer> get_peer(int p_peer_id) const override; + void disconnect_from_host(int p_code = 1000, String p_reason = "") override; + IPAddress get_connected_host() const override; + uint16_t get_connected_port() const override; + virtual ConnectionStatus get_connection_status() const override; + int get_max_packet_size() const override; + virtual void poll() override; EMWSClient(); ~EMWSClient(); }; diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h index df63d2d801..6bb4552c37 100644 --- a/modules/websocket/emws_peer.h +++ b/modules/websocket/emws_peer.h @@ -68,21 +68,21 @@ private: public: Error read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string); void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size); - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - virtual int get_max_packet_size() const { return _packet_buffer.size(); }; - virtual int get_current_outbound_buffered_amount() const; + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_max_packet_size() const override { return _packet_buffer.size(); }; + virtual int get_current_outbound_buffered_amount() const override; - virtual void close(int p_code = 1000, String p_reason = ""); - virtual bool is_connected_to_host() const; - virtual IPAddress get_connected_host() const; - virtual uint16_t get_connected_port() const; + virtual void close(int p_code = 1000, String p_reason = "") override; + virtual bool is_connected_to_host() const override; + virtual IPAddress get_connected_host() const override; + virtual uint16_t get_connected_port() const override; - virtual WriteMode get_write_mode() const; - virtual void set_write_mode(WriteMode p_mode); - virtual bool was_string_packet() const; - virtual void set_no_delay(bool p_enabled); + virtual WriteMode get_write_mode() const override; + virtual void set_write_mode(WriteMode p_mode) override; + virtual bool was_string_packet() const override; + virtual void set_no_delay(bool p_enabled) override; EMWSPeer(); ~EMWSPeer(); diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h index f310c17c9d..0d193d423a 100644 --- a/modules/websocket/emws_server.h +++ b/modules/websocket/emws_server.h @@ -41,17 +41,17 @@ class EMWSServer : public WebSocketServer { GDCIIMPL(EMWSServer, WebSocketServer); public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false); - void stop(); - bool is_listening() const; - bool has_peer(int p_id) const; - Ref<WebSocketPeer> get_peer(int p_id) const; - IPAddress get_peer_address(int p_peer_id) const; - int get_peer_port(int p_peer_id) const; - void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); - int get_max_packet_size() const; - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override; + void stop() override; + bool is_listening() const override; + bool has_peer(int p_id) const override; + Ref<WebSocketPeer> get_peer(int p_id) const override; + IPAddress get_peer_address(int p_peer_id) const override; + int get_peer_port(int p_peer_id) const override; + void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override; + int get_max_packet_size() const override; + virtual void poll() override; virtual Vector<String> get_protocols() const; EMWSServer(); diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h index 84f9506625..3227065ded 100644 --- a/modules/websocket/remote_debugger_peer_websocket.h +++ b/modules/websocket/remote_debugger_peer_websocket.h @@ -51,14 +51,14 @@ public: static RemoteDebuggerPeer *create(const String &p_uri); Error connect_to_host(const String &p_uri); - bool is_peer_connected(); - int get_max_message_size() const; - bool has_message(); - Error put_message(const Array &p_arr); - Array get_message(); - void close(); - void poll(); - bool can_block() const; + bool is_peer_connected() override; + int get_max_message_size() const override; + bool has_message() override; + Error put_message(const Array &p_arr) override; + Array get_message() override; + void close() override; + void poll() override; + bool can_block() const override; RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer = Ref<WebSocketPeer>()); }; diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h index d846e6be00..22b3a4f373 100644 --- a/modules/websocket/wsl_client.h +++ b/modules/websocket/wsl_client.h @@ -73,15 +73,15 @@ private: bool _verify_headers(String &r_protocol); public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()); - int get_max_packet_size() const; - Ref<WebSocketPeer> get_peer(int p_peer_id) const; - void disconnect_from_host(int p_code = 1000, String p_reason = ""); - IPAddress get_connected_host() const; - uint16_t get_connected_port() const; - virtual ConnectionStatus get_connection_status() const; - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override; + int get_max_packet_size() const override; + Ref<WebSocketPeer> get_peer(int p_peer_id) const override; + void disconnect_from_host(int p_code = 1000, String p_reason = "") override; + IPAddress get_connected_host() const override; + uint16_t get_connected_port() const override; + virtual ConnectionStatus get_connection_status() const override; + virtual void poll() override; WSLClient(); ~WSLClient(); diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index d277eedace..15df4d039c 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -146,17 +146,17 @@ void wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event if (!peer_data->valid || peer_data->closing) { return; } - WSLPeer *peer = (WSLPeer *)peer_data->peer; + WSLPeer *peer = static_cast<WSLPeer *>(peer_data->peer); if (peer->parse_message(arg) != OK) { return; } if (peer_data->is_server) { - WSLServer *helper = (WSLServer *)peer_data->obj; + WSLServer *helper = static_cast<WSLServer *>(peer_data->obj); helper->_on_peer_packet(peer_data->id); } else { - WSLClient *helper = (WSLClient *)peer_data->obj; + WSLClient *helper = static_cast<WSLClient *>(peer_data->obj); helper->_on_peer_packet(); } } @@ -184,10 +184,10 @@ Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) { } if (!wslay_event_get_close_sent(_data->ctx)) { if (_data->is_server) { - WSLServer *helper = (WSLServer *)_data->obj; + WSLServer *helper = static_cast<WSLServer *>(_data->obj); helper->_on_close_request(_data->id, close_code, close_reason); } else { - WSLClient *helper = (WSLClient *)_data->obj; + WSLClient *helper = static_cast<WSLClient *>(_data->obj); helper->_on_close_request(close_code, close_reason); } } diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h index 555559c6e1..abeecdd537 100644 --- a/modules/websocket/wsl_peer.h +++ b/modules/websocket/wsl_peer.h @@ -85,22 +85,22 @@ public: String close_reason; void poll(); // Used by client and server. - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - virtual int get_max_packet_size() const { return _packet_buffer.size(); }; - virtual int get_current_outbound_buffered_amount() const; + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_max_packet_size() const override { return _packet_buffer.size(); }; + virtual int get_current_outbound_buffered_amount() const override; virtual void close_now(); - virtual void close(int p_code = 1000, String p_reason = ""); - virtual bool is_connected_to_host() const; - virtual IPAddress get_connected_host() const; - virtual uint16_t get_connected_port() const; - - virtual WriteMode get_write_mode() const; - virtual void set_write_mode(WriteMode p_mode); - virtual bool was_string_packet() const; - virtual void set_no_delay(bool p_enabled); + virtual void close(int p_code = 1000, String p_reason = "") override; + virtual bool is_connected_to_host() const override; + virtual IPAddress get_connected_host() const override; + virtual uint16_t get_connected_port() const override; + + virtual WriteMode get_write_mode() const override; + virtual void set_write_mode(WriteMode p_mode) override; + virtual bool was_string_packet() const override; + virtual void set_no_delay(bool p_enabled) override; void make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size); Error parse_message(const wslay_event_on_msg_recv_arg *arg); diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index eadd7ef7ac..8cd4b78ab3 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -183,7 +183,7 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp void WSLServer::poll() { List<int> remove_ids; for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) { - Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr(); + Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr())); peer->poll(); if (!peer->is_connected_to_host()) { _on_disconnect(E.key, peer->close_code != -1); @@ -266,7 +266,7 @@ int WSLServer::get_max_packet_size() const { void WSLServer::stop() { _server->stop(); for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) { - Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr(); + Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr())); peer->close_now(); } _pending.clear(); diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h index 221cae4793..6a9dd0dd2f 100644 --- a/modules/websocket/wsl_server.h +++ b/modules/websocket/wsl_server.h @@ -75,17 +75,17 @@ private: Vector<String> _protocols; public: - Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); - Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false); - void stop(); - bool is_listening() const; - int get_max_packet_size() const; - bool has_peer(int p_id) const; - Ref<WebSocketPeer> get_peer(int p_id) const; - IPAddress get_peer_address(int p_peer_id) const; - int get_peer_port(int p_peer_id) const; - void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); - virtual void poll(); + Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override; + Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override; + void stop() override; + bool is_listening() const override; + int get_max_packet_size() const override; + bool has_peer(int p_id) const override; + Ref<WebSocketPeer> get_peer(int p_id) const override; + IPAddress get_peer_address(int p_peer_id) const override; + int get_peer_port(int p_peer_id) const override; + void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override; + virtual void poll() override; WSLServer(); ~WSLServer(); |