diff options
Diffstat (limited to 'modules')
105 files changed, 3882 insertions, 1833 deletions
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub index a44a7f0db3..161b0f3814 100644 --- a/modules/basis_universal/SCsub +++ b/modules/basis_universal/SCsub @@ -40,12 +40,12 @@ if not env.msvc: else: env_basisu.Prepend(CPPPATH=[thirdparty_dir]) -if env["target"] == "debug": +if env.dev_build: env_basisu.Append(CPPDEFINES=[("BASISU_DEVEL_MESSAGES", 1), ("BASISD_ENABLE_DEBUG_FLAGS", 1)]) env_thirdparty = env_basisu.Clone() env_thirdparty.disable_warnings() -if env["tools"]: +if env.editor_build: env_thirdparty.Append(CPPDEFINES=["BASISU_NO_IMG_LOADERS"]) env_thirdparty.add_source_files(thirdparty_obj, encoder_sources) env_thirdparty.add_source_files(thirdparty_obj, transcoder_sources) diff --git a/modules/csg/SCsub b/modules/csg/SCsub index 55f859db11..1cf9974fc1 100644 --- a/modules/csg/SCsub +++ b/modules/csg/SCsub @@ -7,5 +7,5 @@ env_csg = env_modules.Clone() # Godot source files env_csg.add_source_files(env.modules_sources, "*.cpp") -if env["tools"]: +if env.editor_build: env_csg.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 738e3d68ea..aae99c52a3 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -39,7 +39,6 @@ #include "core/object/ref_counted.h" #include "core/templates/list.h" #include "core/templates/oa_hash_map.h" -#include "core/templates/rb_map.h" #include "core/templates/vector.h" #include "scene/resources/material.h" diff --git a/modules/cvtt/config.py b/modules/cvtt/config.py index 53b8f2f2e3..eb565b85b9 100644 --- a/modules/cvtt/config.py +++ b/modules/cvtt/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return env["tools"] + return env.editor_build def configure(env): diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub index 97feea2b44..779ce165d2 100644 --- a/modules/denoise/SCsub +++ b/modules/denoise/SCsub @@ -103,9 +103,9 @@ env_oidn.Append( "__STDC_LIMIT_MACROS", "DISABLE_VERBOSE", "MKLDNN_ENABLE_CONCURRENT_EXEC", - "NDEBUG", ] ) +env_oidn.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds. env_thirdparty = env_oidn.Clone() env_thirdparty.disable_warnings() diff --git a/modules/denoise/config.py b/modules/denoise/config.py index 20a5e1da2f..27d2ffbf86 100644 --- a/modules/denoise/config.py +++ b/modules/denoise/config.py @@ -5,7 +5,7 @@ def can_build(env, platform): # as doing lightmap generation and denoising on Android or Web # would be a bit far-fetched. desktop_platforms = ["linuxbsd", "macos", "windows"] - return env["tools"] and platform in desktop_platforms and env["arch"] == "x86_64" + return env.editor_build and platform in desktop_platforms and env["arch"] == "x86_64" def configure(env): diff --git a/modules/etcpak/config.py b/modules/etcpak/config.py index 53b8f2f2e3..eb565b85b9 100644 --- a/modules/etcpak/config.py +++ b/modules/etcpak/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return env["tools"] + return env.editor_build def configure(env): diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index 2680479acc..0b86bc569f 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -90,7 +90,7 @@ if env["builtin_freetype"]: env.Prepend(CPPPATH=[thirdparty_dir + "/include"]) env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", "FT_CONFIG_OPTION_SYSTEM_ZLIB"]) - if env["target"] == "debug": + if env.dev_build: env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) # Also requires libpng headers diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index 2f507db548..1dc4768186 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -7,7 +7,7 @@ env_gdscript = env_modules.Clone() env_gdscript.add_source_files(env.modules_sources, "*.cpp") -if env["tools"]: +if env.editor_build: env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp") SConscript("editor/script_templates/SCsub") diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 6cf8c1a30e..d0b4632ebe 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -84,7 +84,7 @@ <method name="get_stack"> <return type="Array" /> <description> - Returns an array of dictionaries representing the current call stack. + Returns an array of dictionaries representing the current call stack. See also [method print_stack]. [codeblock] func _ready(): foo() @@ -99,6 +99,7 @@ [codeblock] [{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}] [/codeblock] + [b]Note:[/b] [method get_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server. [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array. </description> </method> @@ -175,11 +176,12 @@ <method name="print_stack"> <return type="void" /> <description> - Prints a stack trace at the current code location. Only works when running with debugger turned on. + Prints a stack trace at the current code location. See also [method get_stack]. Output in the console would look something like this: [codeblock] Frame 0 - res://test.gd:16 in function '_process' [/codeblock] + [b]Note:[/b] [method print_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server. [b]Note:[/b] Not supported for calling from threads. Instead of the stack trace, this will print the thread ID. </description> </method> @@ -448,7 +450,7 @@ <param index="1" name="prefix" type="String" default="""" /> <description> Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. Groups can be added with an optional [param prefix], which would make group to only consider properties that have this prefix. The grouping will break on the first property that doesn't have a prefix. The prefix is also removed from the property's name in the Inspector dock. - If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for paramters, [code]@export_group("", "")[/code]. + If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for parameters, [code]@export_group("", "")[/code]. Groups cannot be nested, use [annotation @export_subgroup] to add subgroups to your groups. See also [constant PROPERTY_USAGE_GROUP]. [codeblock] diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index afb59b486c..8b27307d0c 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -39,30 +39,32 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l Type next_type = NONE; Type current_type = NONE; - Type previous_type = NONE; - - String previous_text = ""; - int previous_column = 0; + Type prev_type = NONE; + String prev_text = ""; + int prev_column = 0; bool prev_is_char = false; bool prev_is_digit = false; bool prev_is_binary_op = false; + bool in_keyword = false; bool in_word = false; bool in_number = false; - bool in_function_name = false; - bool in_lambda = false; - bool in_variable_declaration = false; - bool in_signal_declaration = false; - bool in_function_args = false; - bool in_member_variable = false; bool in_node_path = false; bool in_node_ref = false; bool in_annotation = false; bool in_string_name = false; bool is_hex_notation = false; bool is_bin_notation = false; + bool in_member_variable = false; + bool in_lambda = false; + + bool in_function_name = false; + bool in_function_args = false; + bool in_variable_declaration = false; + bool in_signal_declaration = false; bool expect_type = false; + Color keyword_color; Color color; @@ -224,9 +226,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - previous_type = REGION; - previous_text = ""; - previous_column = j; + prev_type = REGION; + prev_text = ""; + prev_column = j; j = from + (end_key_length - 1); if (region_end_index == -1) { color_region_cache[p_line] = in_region; @@ -241,19 +243,22 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - // A bit of a hack, but couldn't come up with anything better. + // VERY hacky... but couldn't come up with anything better. if (j > 0 && (str[j] == '&' || str[j] == '^' || str[j] == '%' || str[j] == '+' || str[j] == '-' || str[j] == '~' || str[j] == '.')) { - if (!keywords.has(previous_text)) { - if (previous_text == "PI" || previous_text == "TAU" || previous_text == "INF" || previous_text == "NAN") { + int to = j - 1; + // Find what the last text was (prev_text won't work if there's no whitespace, so we need to do it manually). + while (to > 0 && is_whitespace(str[to])) { + to--; + } + int from = to; + while (from > 0 && !is_symbol(str[from])) { + from--; + } + String word = str.substr(from + 1, to - from); + // Keywords need to be exceptions, except for keywords that represent a value. + if (word == "true" || word == "false" || word == "null" || word == "PI" || word == "TAU" || word == "INF" || word == "NAN" || word == "self" || word == "super" || !keywords.has(word)) { + if (!is_symbol(str[to]) || str[to] == '"' || str[to] == '\'' || str[to] == ')' || str[to] == ']' || str[to] == '}') { is_binary_op = true; - } else { - int k = j - 1; - while (k > 0 && is_whitespace(str[k])) { - k--; - } - if (!is_symbol(str[k]) || str[k] == '"' || str[k] == '\'' || str[k] == ')' || str[k] == ']' || str[k] == '}') { - is_binary_op = true; - } } } } @@ -287,16 +292,18 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l is_hex_notation = true; } else if (!((str[j] == '-' || str[j] == '+') && str[j - 1] == 'e' && !prev_is_digit) && !(str[j] == '_' && (prev_is_digit || str[j - 1] == 'b' || str[j - 1] == 'x' || str[j - 1] == '.')) && - !((str[j] == 'e' || str[j] == '.') && (prev_is_digit || str[j - 1] == '_')) && + !(str[j] == 'e' && (prev_is_digit || str[j - 1] == '_')) && + !(str[j] == '.' && (prev_is_digit || (!prev_is_binary_op && (j > 0 && (str[j - 1] == '-' || str[j - 1] == '+' || str[j - 1] == '~'))))) && !((str[j] == '-' || str[j] == '+' || str[j] == '~') && !prev_is_binary_op && str[j - 1] != 'e')) { - /* 1st row of condition: '+' or '-' after scientific notation; - 2nd row of condition: '_' as a numeric separator; - 3rd row of condition: Scientific notation 'e' and floating points; - 4th row of condition: Multiple unary operators. */ + /* This condition continues Number highlighting in special cases. + 1st row: '+' or '-' after scientific notation; + 2nd row: '_' as a numeric separator; + 3rd row: Scientific notation 'e' and floating points; + 4th row: Floating points inside the number, or leading if after a unary mathematical operator; + 5th row: Multiple unary mathematical operators */ in_number = false; } - } else if ((str[j] == '-' || str[j] == '+' || str[j] == '~' || (str[j] == '.' && str[j + 1] != '.' && (j == 0 || (j > 0 && str[j - 1] != '.')))) && !is_binary_op) { - // Start a number from unary mathematical operators and floating points, except for '..' + } else if (!is_binary_op && (str[j] == '-' || str[j] == '+' || str[j] == '~' || (str[j] == '.' && str[j + 1] != '.' && (j == 0 || (j > 0 && str[j - 1] != '.'))))) { in_number = true; } @@ -318,7 +325,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l Color col = Color(); if (global_functions.has(word)) { // "assert" and "preload" are reserved, so highlight even if not followed by a bracket. - if (word == "assert" || word == "preload") { + if (word == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::ASSERT) || word == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::PRELOAD)) { col = global_function_color; } else { // For other global functions, check if followed by bracket. @@ -355,7 +362,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } if (!in_function_name && in_word && !in_keyword) { - if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::SIGNAL)) { + if (prev_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::SIGNAL)) { in_signal_declaration = true; } else { int k = j; @@ -370,12 +377,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (str[k] == '(') { in_function_name = true; - } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { + } else if (prev_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { in_variable_declaration = true; } // Check for lambda. - if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { + if (in_function_name && prev_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { k = j - 1; while (k > 0 && is_whitespace(str[k])) { k--; @@ -408,11 +415,11 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_function_args = false; } - if (expect_type && (prev_is_char || str[j] == '=')) { + if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[') { expect_type = false; } - if (j > 0 && str[j] == '>' && str[j - 1] == '-') { + if (j > 0 && str[j - 1] == '-' && str[j] == '>') { expect_type = true; } @@ -491,7 +498,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } else if (in_function_name) { next_type = FUNCTION; - if (!in_lambda && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { + if (!in_lambda && prev_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { color = function_definition_color; } else { color = function_color; @@ -513,20 +520,20 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (current_type == NONE) { current_type = next_type; } else { - previous_type = current_type; + prev_type = current_type; current_type = next_type; // no need to store regions... - if (previous_type == REGION) { - previous_text = ""; - previous_column = j; + if (prev_type == REGION) { + prev_text = ""; + prev_column = j; } else { - String text = str.substr(previous_column, j - previous_column).strip_edges(); - previous_column = j; + String text = str.substr(prev_column, j - prev_column).strip_edges(); + prev_column = j; // ignore if just whitespace if (!text.is_empty()) { - previous_text = text; + prev_text = text; } } } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 1cff2181af..54cadf7df3 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -2390,7 +2390,7 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str } Error err; - Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err); + Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE); // TODO: Reintroduce binary and encrypted scripts. diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index c25f5b58d5..271296c2f9 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -183,20 +183,26 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri return script; } -Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner) { +Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner, bool p_update_from_disk) { MutexLock lock(singleton->lock); if (!p_owner.is_empty()) { singleton->dependencies[p_owner].insert(p_path); } + Ref<GDScript> script; r_error = OK; if (singleton->full_gdscript_cache.has(p_path)) { - return singleton->full_gdscript_cache[p_path]; + script = Ref<GDScript>(singleton->full_gdscript_cache[p_path]); + if (!p_update_from_disk) { + return script; + } } - Ref<GDScript> script = get_shallow_script(p_path); - ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>()); + if (script.is_null()) { + script = get_shallow_script(p_path); + ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>()); + } r_error = script->load_source_code(p_path); diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index b971bdd984..3d111ea229 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -88,7 +88,7 @@ public: static Ref<GDScriptParserRef> get_parser(const String &p_path, GDScriptParserRef::Status status, Error &r_error, const String &p_owner = String()); static String get_source_code(const String &p_path); static Ref<GDScript> get_shallow_script(const String &p_path, const String &p_owner = String()); - static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String()); + static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String(), bool p_update_from_disk = false); static Error finish_compiling(const String &p_owner); GDScriptCache(); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 00e8223b9a..fd418ced47 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2041,7 +2041,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ codegen.generator->write_newline(field->initializer->start_line); // For typed arrays we need to make sure this is already initialized correctly so typed assignment work. - if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type()) { + if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY) { if (field_type.has_container_element_type()) { codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>()); } else { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d8a06a8663..980a946e23 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2932,11 +2932,16 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre // Allow for trailing comma. break; } + bool use_identifier_completion = current.cursor_place == GDScriptTokenizer::CURSOR_END || current.cursor_place == GDScriptTokenizer::CURSOR_MIDDLE; ExpressionNode *argument = parse_expression(false); if (argument == nullptr) { push_error(R"(Expected expression as the function argument.)"); } else { call->arguments.push_back(argument); + + if (argument->type == Node::IDENTIFIER && use_identifier_completion) { + completion_context.type = COMPLETION_IDENTIFIER; + } } ct = COMPLETION_CALL_ARGUMENTS; } while (match(GDScriptTokenizer::Token::COMMA)); @@ -4001,7 +4006,7 @@ String GDScriptParser::DataType::to_string() const { if (is_meta_type) { return script_type->get_class_name().operator String(); } - String name = script_type->get_name(); + String name = script_type != nullptr ? script_type->get_name() : ""; if (!name.is_empty()) { return name; } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 5ad9680ea0..ccde0521f2 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -422,6 +422,7 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin if (error == OK) { if (script->load_source_code(path) == OK) { script->reload(true); + ScriptEditor::get_singleton()->reload_scripts(true); // Refresh scripts opened in the internal editor. } } } diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub index 5f111165fd..d1f337715f 100644 --- a/modules/gltf/SCsub +++ b/modules/gltf/SCsub @@ -9,5 +9,5 @@ env_gltf = env_modules.Clone() env_gltf.add_source_files(env.modules_sources, "*.cpp") env_gltf.add_source_files(env.modules_sources, "structures/*.cpp") SConscript("extensions/SCsub") -if env["tools"]: +if env.editor_build: env_gltf.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index ab52761e17..f79731dd22 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -261,7 +261,7 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li #define ADD_OPTION_ENUM(PATH, ENUM_HINT, VALUE) \ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, SNAME(PATH), PROPERTY_HINT_ENUM, ENUM_HINT), VALUE)); - ADD_OPTION_ENUM("blender/nodes/visible", "Visible Only,Renderable,All", BLEND_VISIBLE_ALL); + ADD_OPTION_ENUM("blender/nodes/visible", "All,Visible Only,Renderable", BLEND_VISIBLE_ALL); ADD_OPTION_BOOL("blender/nodes/punctual_lights", true); ADD_OPTION_BOOL("blender/nodes/cameras", true); ADD_OPTION_BOOL("blender/nodes/custom_properties", true); diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index dd1c1b9889..a1485ff82e 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -45,9 +45,9 @@ class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter { public: enum { + BLEND_VISIBLE_ALL, BLEND_VISIBLE_VISIBLE_ONLY, - BLEND_VISIBLE_RENDERABLE, - BLEND_VISIBLE_ALL + BLEND_VISIBLE_RENDERABLE }; enum { BLEND_BONE_INFLUENCES_NONE, diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h index 90b9a83c88..bf2730d2ef 100644 --- a/modules/gltf/register_types.h +++ b/modules/gltf/register_types.h @@ -28,7 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GLTF_REGISTER_TYPES_H +#define GLTF_REGISTER_TYPES_H + #include "modules/register_module_types.h" void initialize_gltf_module(ModuleInitializationLevel p_level); void uninitialize_gltf_module(ModuleInitializationLevel p_level); + +#endif // GLTF_REGISTER_TYPES_H diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub index da3f7d4dd9..282d772592 100644 --- a/modules/gridmap/SCsub +++ b/modules/gridmap/SCsub @@ -7,5 +7,5 @@ env_gridmap = env_modules.Clone() # Godot source files env_gridmap.add_source_files(env.modules_sources, "*.cpp") -if env["tools"]: +if env.editor_build: env_gridmap.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index ed6cb8656a..0f3662c3cf 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -57,7 +57,7 @@ <return type="Basis" /> <param index="0" name="position" type="Vector3i" /> <description> - Returns the basis that gives the specificed cell its orientation. + Returns the basis that gives the specified cell its orientation. </description> </method> <method name="get_cell_item_orientation" qualifiers="const"> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 466a2efd21..05ce2b6147 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -1149,7 +1149,7 @@ TypedArray<Vector3i> GridMap::get_used_cells() const { TypedArray<Vector3i> GridMap::get_used_cells_by_item(int p_item) const { TypedArray<Vector3i> a; for (const KeyValue<IndexKey, Cell> &E : cell_map) { - if (E.value.item == p_item) { + if ((int)E.value.item == p_item) { Vector3i p(E.key.x, E.key.y, E.key.z); a.push_back(p); } diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 98bcdea8f4..acb92b25e1 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -104,7 +104,7 @@ float AudioStreamPlaybackMP3::get_stream_sampling_rate() { return mp3_stream->sample_rate; } -void AudioStreamPlaybackMP3::start(float p_from_pos) { +void AudioStreamPlaybackMP3::start(double p_from_pos) { active = true; seek(p_from_pos); loops = 0; @@ -123,11 +123,11 @@ int AudioStreamPlaybackMP3::get_loop_count() const { return loops; } -float AudioStreamPlaybackMP3::get_playback_position() const { - return float(frames_mixed) / mp3_stream->sample_rate; +double AudioStreamPlaybackMP3::get_playback_position() const { + return double(frames_mixed) / mp3_stream->sample_rate; } -void AudioStreamPlaybackMP3::seek(float p_time) { +void AudioStreamPlaybackMP3::seek(double p_time) { if (!active) { return; } @@ -217,15 +217,15 @@ bool AudioStreamMP3::has_loop() const { return loop; } -void AudioStreamMP3::set_loop_offset(float p_seconds) { +void AudioStreamMP3::set_loop_offset(double p_seconds) { loop_offset = p_seconds; } -float AudioStreamMP3::get_loop_offset() const { +double AudioStreamMP3::get_loop_offset() const { return loop_offset; } -float AudioStreamMP3::get_length() const { +double AudioStreamMP3::get_length() const { return length; } diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h index 428ac1240e..c34c1dc5fa 100644 --- a/modules/minimp3/audio_stream_mp3.h +++ b/modules/minimp3/audio_stream_mp3.h @@ -61,14 +61,14 @@ protected: virtual float get_stream_sampling_rate() override; public: - virtual void start(float p_from_pos = 0.0) override; + virtual void start(double p_from_pos = 0.0) override; virtual void stop() override; virtual bool is_playing() const override; virtual int get_loop_count() const override; //times it looped - virtual float get_playback_position() const override; - virtual void seek(float p_time) override; + virtual double get_playback_position() const override; + virtual void seek(double p_time) override; virtual void tag_used_streams() override; @@ -104,8 +104,8 @@ public: void set_loop(bool p_enable); virtual bool has_loop() const override; - void set_loop_offset(float p_seconds); - float get_loop_offset() const; + void set_loop_offset(double p_seconds); + double get_loop_offset() const; void set_bpm(double p_bpm); virtual double get_bpm() const override; @@ -122,7 +122,7 @@ public: void set_data(const Vector<uint8_t> &p_data); Vector<uint8_t> get_data() const; - virtual float get_length() const override; + virtual double get_length() const override; virtual bool is_monophonic() const override; diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 7764ba0b45..a4667f784d 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -26,6 +26,6 @@ if env["platform"] in ["macos", "ios"]: elif env["platform"] == "android": env_mono.add_source_files(env.modules_sources, "mono_gd/android_mono_config.gen.cpp") -if env["tools"]: +if env.editor_build: env_mono.add_source_files(env.modules_sources, "editor/*.cpp") SConscript("editor/script_templates/SCsub") diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py index d78a9c7db8..d28c3a0c3a 100755 --- a/modules/mono/build_scripts/build_assemblies.py +++ b/modules/mono/build_scripts/build_assemblies.py @@ -5,6 +5,7 @@ import os.path import shlex import subprocess from dataclasses import dataclass +from typing import Optional, List def find_dotnet_cli(): @@ -150,10 +151,7 @@ def find_any_msbuild_tool(mono_prefix): return None -def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None): - if msbuild_args is None: - msbuild_args = [] - +def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: Optional[List[str]] = None): using_msbuild_mono = False # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild @@ -169,7 +167,7 @@ def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None): args += [sln] - if len(msbuild_args) > 0: + if msbuild_args: args += msbuild_args print("Running MSBuild: ", " ".join(shlex.quote(arg) for arg in args), flush=True) diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 5d63773096..5cec8f41f5 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -20,10 +20,7 @@ def configure(env, env_mono): # is_ios = env["platform"] == "ios" # is_ios_sim = is_ios and env["arch"] in ["x86_32", "x86_64"] - tools_enabled = env["tools"] - - if tools_enabled and not module_supports_tools_on(env["platform"]): - raise RuntimeError("This module does not currently support building for this platform with tools enabled") - - if env["tools"]: + if env.editor_build: + if not module_supports_tools_on(env["platform"]): + raise RuntimeError("This module does not currently support building for this platform for editor builds.") env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"]) diff --git a/modules/mono/config.py b/modules/mono/config.py index 15fe79ef8c..a36083b64b 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -7,7 +7,7 @@ def can_build(env, platform): if env["arch"].startswith("rv"): return False - if env["tools"]: + if env.editor_build: env.module_add_dependencies("mono", ["regex"]) return True diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index eeda1042ca..ea7cc3fe38 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Text; // TODO: // Determine a proper way to emit the signal. -// 'Emit(nameof(TheEvent))' creates a StringName everytime and has the overhead of string marshaling. +// 'Emit(nameof(TheEvent))' creates a StringName every time and has the overhead of string marshaling. // I haven't decided on the best option yet. Some possibilities: // - Expose the generated StringName fields to the user, for use with 'Emit(...)'. // - Generate a 'EmitSignalName' method for each event signal. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index fbd59d649f..9c3bc51c44 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -4,6 +4,21 @@ using System.Runtime.InteropServices; namespace Godot { /// <summary> + /// Specifies which order Euler angle rotations should be in. + /// When composing, the order is the same as the letters. When decomposing, + /// the order is reversed (ex: YXZ decomposes Z first, then X, and Y last). + /// </summary> + public enum EulerOrder + { + XYZ, + XZY, + YXZ, + YZX, + ZXY, + ZYX + }; + + /// <summary> /// 3×3 matrix used for 3D rotation and scale. /// Almost always used as an orthogonal basis for a Transform. /// @@ -244,50 +259,258 @@ namespace Godot } /// <summary> - /// Returns the basis's rotation in the form of Euler angles - /// (in the YXZ convention: when *decomposing*, first Z, then X, and Y last). - /// The returned vector contains the rotation angles in - /// the format (X angle, Y angle, Z angle). + /// Returns the basis's rotation in the form of Euler angles. + /// The Euler order depends on the [param order] parameter, + /// by default it uses the YXZ convention: when decomposing, + /// first Z, then X, and Y last. The returned vector contains + /// the rotation angles in the format (X angle, Y angle, Z angle). /// /// Consider using the <see cref="GetRotationQuaternion"/> method instead, which /// returns a <see cref="Quaternion"/> quaternion instead of Euler angles. /// </summary> + /// <param name="order">The Euler order to use. By default, use YXZ order (most common).</param> /// <returns>A <see cref="Vector3"/> representing the basis rotation in Euler angles.</returns> - public Vector3 GetEuler() + public Vector3 GetEuler(EulerOrder order = EulerOrder.YXZ) { - Basis m = Orthonormalized(); - - Vector3 euler; - euler.z = 0.0f; - - real_t mzy = m.Row1[2]; - - if (mzy < 1.0f) + switch (order) { - if (mzy > -1.0f) + case EulerOrder.XYZ: { - euler.x = Mathf.Asin(-mzy); - euler.y = Mathf.Atan2(m.Row0[2], m.Row2[2]); - euler.z = Mathf.Atan2(m.Row1[0], m.Row1[1]); + // Euler angles in XYZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz -cy*sz sy + // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx + // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy + Vector3 euler; + real_t sy = Row0[2]; + if (sy < (1.0f - Mathf.Epsilon)) + { + if (sy > -(1.0f - Mathf.Epsilon)) + { + // is this a pure Y rotation? + if (Row1[0] == 0 && Row0[1] == 0 && Row1[2] == 0 && Row2[1] == 0 && Row1[1] == 1) + { + // return the simplest form (human friendlier in editor and scripts) + euler.x = 0; + euler.y = Mathf.Atan2(Row0[2], Row0[0]); + euler.z = 0; + } + else + { + euler.x = Mathf.Atan2(-Row1[2], Row2[2]); + euler.y = Mathf.Asin(sy); + euler.z = Mathf.Atan2(-Row0[1], Row0[0]); + } + } + else + { + euler.x = Mathf.Atan2(Row2[1], Row1[1]); + euler.y = -Mathf.Tau / 4.0f; + euler.z = 0.0f; + } + } + else + { + euler.x = Mathf.Atan2(Row2[1], Row1[1]); + euler.y = Mathf.Tau / 4.0f; + euler.z = 0.0f; + } + return euler; } - else + case EulerOrder.XZY: { - euler.x = Mathf.Pi * 0.5f; - euler.y = -Mathf.Atan2(-m.Row0[1], m.Row0[0]); + // Euler angles in XZY convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy -sz cz*sy + // sx*sy+cx*cy*sz cx*cz cx*sz*sy-cy*sx + // cy*sx*sz cz*sx cx*cy+sx*sz*sy + Vector3 euler; + real_t sz = Row0[1]; + if (sz < (1.0f - Mathf.Epsilon)) + { + if (sz > -(1.0f - Mathf.Epsilon)) + { + euler.x = Mathf.Atan2(Row2[1], Row1[1]); + euler.y = Mathf.Atan2(Row0[2], Row0[0]); + euler.z = Mathf.Asin(-sz); + } + else + { + // It's -1 + euler.x = -Mathf.Atan2(Row1[2], Row2[2]); + euler.y = 0.0f; + euler.z = Mathf.Tau / 4.0f; + } + } + else + { + // It's 1 + euler.x = -Mathf.Atan2(Row1[2], Row2[2]); + euler.y = 0.0f; + euler.z = -Mathf.Tau / 4.0f; + } + return euler; } - } - else - { - euler.x = -Mathf.Pi * 0.5f; - euler.y = -Mathf.Atan2(-m.Row0[1], m.Row0[0]); - } + case EulerOrder.YXZ: + { + // Euler angles in YXZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy + // cx*sz cx*cz -sx + // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx + Vector3 euler; + real_t m12 = Row1[2]; + if (m12 < (1 - Mathf.Epsilon)) + { + if (m12 > -(1 - Mathf.Epsilon)) + { + // is this a pure X rotation? + if (Row1[0] == 0 && Row0[1] == 0 && Row0[2] == 0 && Row2[0] == 0 && Row0[0] == 1) + { + // return the simplest form (human friendlier in editor and scripts) + euler.x = Mathf.Atan2(-m12, Row1[1]); + euler.y = 0; + euler.z = 0; + } + else + { + euler.x = Mathf.Asin(-m12); + euler.y = Mathf.Atan2(Row0[2], Row2[2]); + euler.z = Mathf.Atan2(Row1[0], Row1[1]); + } + } + else + { // m12 == -1 + euler.x = Mathf.Tau / 4.0f; + euler.y = Mathf.Atan2(Row0[1], Row0[0]); + euler.z = 0; + } + } + else + { // m12 == 1 + euler.x = -Mathf.Tau / 4.0f; + euler.y = -Mathf.Atan2(Row0[1], Row0[0]); + euler.z = 0; + } - return euler; + return euler; + } + case EulerOrder.YZX: + { + // Euler angles in YZX convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx + // sz cz*cx -cz*sx + // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx + Vector3 euler; + real_t sz = Row1[0]; + if (sz < (1.0f - Mathf.Epsilon)) + { + if (sz > -(1.0f - Mathf.Epsilon)) + { + euler.x = Mathf.Atan2(-Row1[2], Row1[1]); + euler.y = Mathf.Atan2(-Row2[0], Row0[0]); + euler.z = Mathf.Asin(sz); + } + else + { + // It's -1 + euler.x = Mathf.Atan2(Row2[1], Row2[2]); + euler.y = 0.0f; + euler.z = -Mathf.Tau / 4.0f; + } + } + else + { + // It's 1 + euler.x = Mathf.Atan2(Row2[1], Row2[2]); + euler.y = 0.0f; + euler.z = Mathf.Tau / 4.0f; + } + return euler; + } + case EulerOrder.ZXY: + { + // Euler angles in ZXY convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx + // cy*sz+cz*sx*sy cz*cx sz*sy-cz*cy*sx + // -cx*sy sx cx*cy + Vector3 euler; + real_t sx = Row2[1]; + if (sx < (1.0f - Mathf.Epsilon)) + { + if (sx > -(1.0f - Mathf.Epsilon)) + { + euler.x = Mathf.Asin(sx); + euler.y = Mathf.Atan2(-Row2[0], Row2[2]); + euler.z = Mathf.Atan2(-Row0[1], Row1[1]); + } + else + { + // It's -1 + euler.x = -Mathf.Tau / 4.0f; + euler.y = Mathf.Atan2(Row0[2], Row0[0]); + euler.z = 0; + } + } + else + { + // It's 1 + euler.x = Mathf.Tau / 4.0f; + euler.y = Mathf.Atan2(Row0[2], Row0[0]); + euler.z = 0; + } + return euler; + } + case EulerOrder.ZYX: + { + // Euler angles in ZYX convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*cy + // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx + // -sy cy*sx cy*cx + Vector3 euler; + real_t sy = Row2[0]; + if (sy < (1.0f - Mathf.Epsilon)) + { + if (sy > -(1.0f - Mathf.Epsilon)) + { + euler.x = Mathf.Atan2(Row2[1], Row2[2]); + euler.y = Mathf.Asin(-sy); + euler.z = Mathf.Atan2(Row1[0], Row0[0]); + } + else + { + // It's -1 + euler.x = 0; + euler.y = Mathf.Tau / 4.0f; + euler.z = -Mathf.Atan2(Row0[1], Row1[1]); + } + } + else + { + // It's 1 + euler.x = 0; + euler.y = -Mathf.Tau / 4.0f; + euler.z = -Mathf.Atan2(Row0[1], Row1[1]); + } + return euler; + } + default: + throw new ArgumentOutOfRangeException(nameof(order)); + } } /// <summary> /// Returns the basis's rotation in the form of a quaternion. - /// See <see cref="GetEuler()"/> if you need Euler angles, but keep in + /// See <see cref="GetEuler"/> if you need Euler angles, but keep in /// mind that quaternions should generally be preferred to Euler angles. /// </summary> /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns> @@ -712,35 +935,6 @@ namespace Godot } /// <summary> - /// Constructs a pure rotation basis matrix from the given Euler angles - /// (in the YXZ convention: when *composing*, first Y, then X, and Z last), - /// given in the vector format as (X angle, Y angle, Z angle). - /// - /// Consider using the <see cref="Basis(Quaternion)"/> constructor instead, which - /// uses a <see cref="Quaternion"/> quaternion instead of Euler angles. - /// </summary> - /// <param name="eulerYXZ">The Euler angles to create the basis from.</param> - public Basis(Vector3 eulerYXZ) - { - real_t c; - real_t s; - - c = Mathf.Cos(eulerYXZ.x); - s = Mathf.Sin(eulerYXZ.x); - var xmat = new Basis(1, 0, 0, 0, c, -s, 0, s, c); - - c = Mathf.Cos(eulerYXZ.y); - s = Mathf.Sin(eulerYXZ.y); - var ymat = new Basis(c, 0, s, 0, 1, 0, -s, 0, c); - - c = Mathf.Cos(eulerYXZ.z); - s = Mathf.Sin(eulerYXZ.z); - var zmat = new Basis(c, -s, 0, s, c, 0, 0, 0, 1); - - this = ymat * xmat * zmat; - } - - /// <summary> /// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/> /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector. /// </summary> @@ -800,6 +994,46 @@ namespace Godot } /// <summary> + /// Constructs a Basis matrix from Euler angles in the specified rotation order. By default, use YXZ order (most common). + /// </summary> + /// <param name="euler">The Euler angles to use.</param> + /// <param name="order">The order to compose the Euler angles.</param> + public static Basis FromEuler(Vector3 euler, EulerOrder order = EulerOrder.YXZ) + { + real_t c, s; + + c = Mathf.Cos(euler.x); + s = Mathf.Sin(euler.x); + Basis xmat = new Basis(new Vector3(1, 0, 0), new Vector3(0, c, s), new Vector3(0, -s, c)); + + c = Mathf.Cos(euler.y); + s = Mathf.Sin(euler.y); + Basis ymat = new Basis(new Vector3(c, 0, -s), new Vector3(0, 1, 0), new Vector3(s, 0, c)); + + c = Mathf.Cos(euler.z); + s = Mathf.Sin(euler.z); + Basis zmat = new Basis(new Vector3(c, s, 0), new Vector3(-s, c, 0), new Vector3(0, 0, 1)); + + switch (order) + { + case EulerOrder.XYZ: + return xmat * ymat * zmat; + case EulerOrder.XZY: + return xmat * zmat * ymat; + case EulerOrder.YXZ: + return ymat * xmat * zmat; + case EulerOrder.YZX: + return ymat * zmat * xmat; + case EulerOrder.ZXY: + return zmat * xmat * ymat; + case EulerOrder.ZYX: + return zmat * ymat * xmat; + default: + throw new ArgumentOutOfRangeException(nameof(order)); + } + } + + /// <summary> /// Constructs a pure scale basis matrix with no rotation or shearing. /// The scale values are set as the main diagonal of the matrix, /// and all of the other parts of the matrix are zero. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index 1b7f5158fd..bdedd2e87a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -72,7 +72,7 @@ namespace Godot /// <param name="delegate">Delegate method that will be called.</param> public Callable(Delegate @delegate) { - _target = null; + _target = @delegate?.Target as Object; _method = null; _delegate = @delegate; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 3483a04c83..ee9e59f9fa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -597,7 +597,7 @@ namespace Godot /// <exception name="ArgumentOutOfRangeException"> /// <paramref name="rgba"/> color code is invalid. /// </exception> - private static Color FromHTML(string rgba) + private static Color FromHTML(ReadOnlySpan<char> rgba) { Color c; if (rgba.Length == 0) @@ -611,7 +611,7 @@ namespace Godot if (rgba[0] == '#') { - rgba = rgba.Substring(1); + rgba = rgba.Slice(1); } // If enabled, use 1 hex digit per channel instead of 2. @@ -665,22 +665,22 @@ namespace Godot if (c.r < 0) { - throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba); + throw new ArgumentOutOfRangeException($"Invalid color code. Red part is not valid hexadecimal: {rgba}"); } if (c.g < 0) { - throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba); + throw new ArgumentOutOfRangeException($"Invalid color code. Green part is not valid hexadecimal: {rgba}"); } if (c.b < 0) { - throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba); + throw new ArgumentOutOfRangeException($"Invalid color code. Blue part is not valid hexadecimal: {rgba}"); } if (c.a < 0) { - throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba); + throw new ArgumentOutOfRangeException($"Invalid color code. Alpha part is not valid hexadecimal: {rgba}"); } return c; } @@ -817,9 +817,9 @@ namespace Godot value = max; } - private static int ParseCol4(string str, int ofs) + private static int ParseCol4(ReadOnlySpan<char> str, int index) { - char character = str[ofs]; + char character = str[index]; if (character >= '0' && character <= '9') { @@ -836,9 +836,9 @@ namespace Godot return -1; } - private static int ParseCol8(string str, int ofs) + private static int ParseCol8(ReadOnlySpan<char> str, int index) { - return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1); + return ParseCol4(str, index) * 16 + ParseCol4(str, index + 1); } private static string ToHex32(float val) @@ -847,16 +847,16 @@ namespace Godot return b.HexEncode(); } - internal static bool HtmlIsValid(string color) + internal static bool HtmlIsValid(ReadOnlySpan<char> color) { - if (string.IsNullOrEmpty(color)) + if (color.IsEmpty) { return false; } if (color[0] == '#') { - color = color.Substring(1); + color = color.Slice(1); } // Check if the amount of hex digits is valid. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 140fc167ba..76b186cd15 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -721,8 +721,9 @@ namespace Godot.NativeInterop if (p_managed_callable.Delegate != null) { var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate); + IntPtr objectPtr = p_managed_callable.Target != null ? Object.GetPtr(p_managed_callable.Target) : IntPtr.Zero; NativeFuncs.godotsharp_callable_new_with_delegate( - GCHandle.ToIntPtr(gcHandle), out godot_callable callable); + GCHandle.ToIntPtr(gcHandle), objectPtr, out godot_callable callable); return callable; } else diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index bd00611383..20ede9f0dd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -141,7 +141,7 @@ namespace Godot.NativeInterop public static partial void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest, in godot_string p_element); - public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, + public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_object, out godot_callable r_callable); internal static partial godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable, diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index 276701cdaa..2717b945f6 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -447,9 +447,10 @@ void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String r_dest->append(*p_element); } -void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, Callable *r_callable) { +void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, const Object *p_object, Callable *r_callable) { // TODO: Use pooling for ManagedCallable instances. - CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle)); + ObjectID objid = p_object ? p_object->get_instance_id() : ObjectID(); + CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle, objid)); memnew_placement(r_callable, Callable(managed_callable)); } diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp index 9305dc645a..0c2c533090 100644 --- a/modules/mono/managed_callable.cpp +++ b/modules/mono/managed_callable.cpp @@ -79,7 +79,9 @@ CallableCustom::CompareLessFunc ManagedCallable::get_compare_less_func() const { } ObjectID ManagedCallable::get_object() const { - // TODO: If the delegate target extends Godot.Object, use that instead! + if (object_id != ObjectID()) { + return object_id; + } return CSharpLanguage::get_singleton()->get_managed_callable_middleman()->get_instance_id(); } @@ -104,7 +106,7 @@ void ManagedCallable::release_delegate_handle() { // Why you do this clang-format... /* clang-format off */ -ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle) : delegate_handle(p_delegate_handle) { +ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id) : delegate_handle(p_delegate_handle), object_id(p_object_id) { #ifdef GD_MONO_HOT_RELOAD { MutexLock lock(instances_mutex); diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h index aa3344f4d5..26cd164fb6 100644 --- a/modules/mono/managed_callable.h +++ b/modules/mono/managed_callable.h @@ -40,6 +40,7 @@ class ManagedCallable : public CallableCustom { friend class CSharpLanguage; GCHandleIntPtr delegate_handle; + ObjectID object_id; #ifdef GD_MONO_HOT_RELOAD SelfList<ManagedCallable> self_instance = this; @@ -66,7 +67,7 @@ public: void release_delegate_handle(); - ManagedCallable(GCHandleIntPtr p_delegate_handle); + ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id); ~ManagedCallable(); }; diff --git a/modules/mono/utils/macos_utils.h b/modules/mono/utils/macos_utils.h index ca4957f5a7..0b74114685 100644 --- a/modules/mono/utils/macos_utils.h +++ b/modules/mono/utils/macos_utils.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/string/ustring.h" - #ifndef MONO_MACOS_UTILS_H #define MONO_MACOS_UTILS_H #ifdef MACOS_ENABLED +#include "core/string/ustring.h" + bool macos_is_app_bundle_installed(const String &p_bundle_id); #endif diff --git a/modules/multiplayer/SCsub b/modules/multiplayer/SCsub index ff33655537..e89038c3e0 100644 --- a/modules/multiplayer/SCsub +++ b/modules/multiplayer/SCsub @@ -8,7 +8,7 @@ env_mp = env_modules.Clone() module_obj = [] env_mp.add_source_files(module_obj, "*.cpp") -if env["tools"]: +if env.editor_build: env_mp.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml index 9a4d755d64..42c190f504 100644 --- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml +++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml @@ -5,7 +5,7 @@ </brief_description> <description> By default, [MultiplayerSynchronizer] synchronizes configured properties to all peers. - Visiblity can be handled directly with [method set_visibility_for] or as-needed with [method add_visibility_filter] and [method update_visibility]. + Visibility can be handled directly with [method set_visibility_for] or as-needed with [method add_visibility_filter] and [method update_visibility]. [MultiplayerSpawner]s will handle nodes according to visibility of synchronizers as long as the node at [member root_path] was spawned by one. @@ -34,7 +34,7 @@ <return type="void" /> <param index="0" name="filter" type="Callable" /> <description> - Removes a peer visiblity filter from this synchronizer. + Removes a peer visibility filter from this synchronizer. </description> </method> <method name="set_visibility_for"> diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp index 9d28feef09..620e4f2f6c 100644 --- a/modules/multiplayer/multiplayer_spawner.cpp +++ b/modules/multiplayer/multiplayer_spawner.cpp @@ -94,7 +94,7 @@ PackedStringArray MultiplayerSpawner::get_configuration_warnings() const { warnings.push_back(RTR("A valid NodePath must be set in the \"Spawn Path\" property in order for MultiplayerSpawner to be able to spawn Nodes.")); } bool has_scenes = get_spawnable_scene_count() > 0; - // Can't check if method is overriden in placeholder scripts. + // Can't check if method is overridden in placeholder scripts. bool has_placeholder_script = get_script_instance() && get_script_instance()->is_placeholder(); if (!has_scenes && !GDVIRTUAL_IS_OVERRIDDEN(_spawn_custom) && !has_placeholder_script) { warnings.push_back(RTR("A list of PackedScenes must be set in the \"Auto Spawn List\" property in order for MultiplayerSpawner to automatically spawn them remotely when added as child of \"spawn_path\".")); diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp index 2c3ebccaeb..9755f426d5 100644 --- a/modules/multiplayer/multiplayer_synchronizer.cpp +++ b/modules/multiplayer/multiplayer_synchronizer.cpp @@ -48,6 +48,8 @@ void MultiplayerSynchronizer::_stop() { return; } #endif + root_node_cache = ObjectID(); + reset(); Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; if (node) { get_multiplayer()->object_configuration_remove(node, this); @@ -60,8 +62,11 @@ void MultiplayerSynchronizer::_start() { return; } #endif + root_node_cache = ObjectID(); + reset(); Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; if (node) { + root_node_cache = node->get_instance_id(); get_multiplayer()->object_configuration_add(node, this); _update_process(); } @@ -94,6 +99,40 @@ void MultiplayerSynchronizer::_update_process() { } } +Node *MultiplayerSynchronizer::get_root_node() { + return root_node_cache.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(root_node_cache)) : nullptr; +} + +void MultiplayerSynchronizer::reset() { + net_id = 0; + last_sync_msec = 0; + last_inbound_sync = 0; +} + +uint32_t MultiplayerSynchronizer::get_net_id() const { + return net_id; +} + +void MultiplayerSynchronizer::set_net_id(uint32_t p_net_id) { + net_id = p_net_id; +} + +bool MultiplayerSynchronizer::update_outbound_sync_time(uint64_t p_msec) { + if (p_msec >= last_sync_msec + interval_msec) { + last_sync_msec = p_msec; + return true; + } + return false; +} + +bool MultiplayerSynchronizer::update_inbound_sync_time(uint16_t p_network_time) { + if (p_network_time <= last_inbound_sync && last_inbound_sync - p_network_time < 32767) { + return false; + } + last_inbound_sync = p_network_time; + return true; +} + PackedStringArray MultiplayerSynchronizer::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); @@ -263,10 +302,6 @@ double MultiplayerSynchronizer::get_replication_interval() const { return double(interval_msec) / 1000.0; } -uint64_t MultiplayerSynchronizer::get_replication_interval_msec() const { - return interval_msec; -} - void MultiplayerSynchronizer::set_replication_config(Ref<SceneReplicationConfig> p_config) { replication_config = p_config; } @@ -299,10 +334,11 @@ NodePath MultiplayerSynchronizer::get_root_path() const { void MultiplayerSynchronizer::set_multiplayer_authority(int p_peer_id, bool p_recursive) { Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; - if (!node) { + if (!node || get_multiplayer_authority() == p_peer_id) { Node::set_multiplayer_authority(p_peer_id, p_recursive); return; } + get_multiplayer()->object_configuration_remove(node, this); Node::set_multiplayer_authority(p_peer_id, p_recursive); get_multiplayer()->object_configuration_add(node, this); diff --git a/modules/multiplayer/multiplayer_synchronizer.h b/modules/multiplayer/multiplayer_synchronizer.h index f10a95a1d4..9a7ce717cd 100644 --- a/modules/multiplayer/multiplayer_synchronizer.h +++ b/modules/multiplayer/multiplayer_synchronizer.h @@ -53,6 +53,11 @@ private: HashSet<Callable> visibility_filters; HashSet<int> peer_visibility; + ObjectID root_node_cache; + uint64_t last_sync_msec = 0; + uint16_t last_inbound_sync = 0; + uint32_t net_id = 0; + static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop); void _start(); void _stop(); @@ -66,11 +71,19 @@ public: static Error get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs); static Error set_state(const List<NodePath> &p_properties, Object *p_obj, const Vector<Variant> &p_state); + void reset(); + Node *get_root_node(); + + uint32_t get_net_id() const; + void set_net_id(uint32_t p_net_id); + + bool update_outbound_sync_time(uint64_t p_msec); + bool update_inbound_sync_time(uint16_t p_network_time); + PackedStringArray get_configuration_warnings() const override; void set_replication_interval(double p_interval); double get_replication_interval() const; - uint64_t get_replication_interval_msec() const; void set_replication_config(Ref<SceneReplicationConfig> p_config); Ref<SceneReplicationConfig> get_replication_config(); diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index 6e3dbfab47..df9985916b 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -30,21 +30,47 @@ #include "scene_replication_interface.h" +#include "scene_multiplayer.h" + #include "core/io/marshalls.h" #include "scene/main/node.h" - -#include "multiplayer_spawner.h" -#include "multiplayer_synchronizer.h" -#include "scene_multiplayer.h" +#include "scene/scene_string_names.h" #define MAKE_ROOM(m_amount) \ if (packet_cache.size() < m_amount) \ packet_cache.resize(m_amount); -void SceneReplicationInterface::_free_remotes(int p_id) { - const HashMap<uint32_t, ObjectID> remotes = rep_state->peer_get_remotes(p_id); - for (const KeyValue<uint32_t, ObjectID> &E : remotes) { - Node *node = rep_state->get_node(E.value); +SceneReplicationInterface::TrackedNode &SceneReplicationInterface::_track(const ObjectID &p_id) { + if (!tracked_nodes.has(p_id)) { + tracked_nodes[p_id] = TrackedNode(p_id); + Node *node = get_id_as<Node>(p_id); + node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationInterface::_untrack).bind(p_id), Node::CONNECT_ONE_SHOT); + } + return tracked_nodes[p_id]; +} + +void SceneReplicationInterface::_untrack(const ObjectID &p_id) { + if (!tracked_nodes.has(p_id)) { + return; + } + uint32_t net_id = tracked_nodes[p_id].net_id; + uint32_t peer = tracked_nodes[p_id].remote_peer; + tracked_nodes.erase(p_id); + // If it was spawned by a remote, remove it from the received nodes. + if (peer && peers_info.has(peer)) { + peers_info[peer].recv_nodes.erase(net_id); + } + // If we spawned or synced it, we need to remove it from any peer it was sent to. + if (net_id || peer == 0) { + for (KeyValue<int, PeerInfo> &E : peers_info) { + E.value.spawn_nodes.erase(p_id); + } + } +} + +void SceneReplicationInterface::_free_remotes(const PeerInfo &p_info) { + for (const KeyValue<uint32_t, ObjectID> &E : p_info.recv_nodes) { + Node *node = tracked_nodes.has(E.value) ? get_id_as<Node>(E.value) : nullptr; ERR_CONTINUE(!node); node->queue_delete(); } @@ -52,34 +78,48 @@ void SceneReplicationInterface::_free_remotes(int p_id) { void SceneReplicationInterface::on_peer_change(int p_id, bool p_connected) { if (p_connected) { - rep_state->on_peer_change(p_id, p_connected); - for (const ObjectID &oid : rep_state->get_spawned_nodes()) { + peers_info[p_id] = PeerInfo(); + for (const ObjectID &oid : spawned_nodes) { _update_spawn_visibility(p_id, oid); } - for (const ObjectID &oid : rep_state->get_synced_nodes()) { - MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); - ERR_CONTINUE(!sync); // ERR_BUG - if (sync->is_multiplayer_authority()) { - _update_sync_visibility(p_id, oid); - } + for (const ObjectID &oid : sync_nodes) { + _update_sync_visibility(p_id, get_id_as<MultiplayerSynchronizer>(oid)); } } else { - _free_remotes(p_id); - rep_state->on_peer_change(p_id, p_connected); + ERR_FAIL_COND(!peers_info.has(p_id)); + _free_remotes(peers_info[p_id]); + peers_info.erase(p_id); } } void SceneReplicationInterface::on_reset() { - for (int pid : rep_state->get_peers()) { - _free_remotes(pid); + for (const KeyValue<int, PeerInfo> &E : peers_info) { + _free_remotes(E.value); + } + peers_info.clear(); + // Tracked nodes are cleared on deletion, here we only reset the ids so they can be later re-assigned. + for (KeyValue<ObjectID, TrackedNode> &E : tracked_nodes) { + TrackedNode &tobj = E.value; + tobj.net_id = 0; + tobj.remote_peer = 0; } - rep_state->reset(); + for (const ObjectID &oid : sync_nodes) { + MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(oid); + ERR_CONTINUE(!sync); + sync->reset(); + } + last_net_id = 0; } void SceneReplicationInterface::on_network_process() { uint64_t msec = OS::get_singleton()->get_ticks_msec(); - for (int peer : rep_state->get_peers()) { - _send_sync(peer, msec); + for (KeyValue<int, PeerInfo> &E : peers_info) { + const HashSet<ObjectID> to_sync = E.value.sync_nodes; + if (to_sync.is_empty()) { + continue; // Nothing to sync + } + uint16_t sync_net_time = ++E.value.last_sent_sync; + _send_sync(E.key, to_sync, sync_net_time, msec); } } @@ -88,14 +128,19 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) { ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object()); ERR_FAIL_COND_V(!spawner, ERR_INVALID_PARAMETER); - Error err = rep_state->config_add_spawn(node, spawner); - ERR_FAIL_COND_V(err != OK, err); + // Track node. const ObjectID oid = node->get_instance_id(); + TrackedNode &tobj = _track(oid); + ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); + tobj.spawner = spawner->get_instance_id(); + spawned_nodes.insert(oid); + if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) { - rep_state->ensure_net_id(oid); + if (tobj.net_id == 0) { + tobj.net_id = ++last_net_id; + } _update_spawn_visibility(0, oid); } - ERR_FAIL_COND_V(err != OK, err); return OK; } @@ -109,14 +154,22 @@ Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) { Error err = _make_despawn_packet(node, len); ERR_FAIL_COND_V(err != OK, ERR_BUG); const ObjectID oid = p_obj->get_instance_id(); - for (int pid : rep_state->get_peers()) { - if (!rep_state->is_peer_spawn(pid, oid)) { + for (const KeyValue<int, PeerInfo> &E : peers_info) { + if (!E.value.spawn_nodes.has(oid)) { continue; } - _send_raw(packet_cache.ptr(), len, pid, true); + _send_raw(packet_cache.ptr(), len, E.key, true); } // Also remove spawner tracking from the replication state. - return rep_state->config_del_spawn(node, spawner); + ERR_FAIL_COND_V(!tracked_nodes.has(oid), ERR_INVALID_PARAMETER); + TrackedNode &tobj = _track(oid); + ERR_FAIL_COND_V(tobj.spawner != spawner->get_instance_id(), ERR_INVALID_PARAMETER); + tobj.spawner = ObjectID(); + spawned_nodes.erase(oid); + for (KeyValue<int, PeerInfo> &E : peers_info) { + E.value.spawn_nodes.erase(oid); + } + return OK; } Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_config) { @@ -125,25 +178,40 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER); - // Add to synchronizer list and setup visibility. - rep_state->config_add_sync(node, sync); - const ObjectID oid = node->get_instance_id(); - sync->connect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed).bind(oid)); - if (multiplayer->has_multiplayer_peer() && sync->is_multiplayer_authority()) { - _update_sync_visibility(0, oid); - } - - // Try to apply initial state if spawning (hack to apply if before ready). - if (pending_spawn == p_obj->get_instance_id()) { - pending_spawn = ObjectID(); // Make sure this only happens once. - const List<NodePath> props = sync->get_replication_config()->get_spawn_properties(); - Vector<Variant> vars; - vars.resize(props.size()); - int consumed; - Error err = MultiplayerAPI::decode_and_decompress_variants(vars, pending_buffer, pending_buffer_size, consumed); - ERR_FAIL_COND_V(err, err); - err = MultiplayerSynchronizer::set_state(props, node, vars); - ERR_FAIL_COND_V(err, err); + // Add to synchronizer list. + TrackedNode &tobj = _track(p_obj->get_instance_id()); + const ObjectID sid = sync->get_instance_id(); + tobj.synchronizers.insert(sid); + sync_nodes.insert(sid); + + // Update visibility. + sync->connect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed).bind(sync->get_instance_id())); + _update_sync_visibility(0, sync); + + if (pending_spawn == p_obj->get_instance_id() && sync->get_multiplayer_authority() == pending_spawn_remote) { + // Try to apply synchronizer Net ID + ERR_FAIL_COND_V_MSG(pending_sync_net_ids.is_empty(), ERR_INVALID_DATA, vformat("The MultiplayerSynchronizer at path \"%s\" is unable to process the pending spawn since it has no network ID. This might happen when changing the multiplayer authority during the \"_ready\" callback. Make sure to only change the authority of multiplayer synchronizers during \"_enter_tree\" or the \"_spawn_custom\" callback of their multiplayer spawner.", sync->get_path())); + ERR_FAIL_COND_V(!peers_info.has(pending_spawn_remote), ERR_INVALID_DATA); + uint32_t net_id = pending_sync_net_ids[0]; + pending_sync_net_ids.pop_front(); + peers_info[pending_spawn_remote].recv_sync_ids[net_id] = sync->get_instance_id(); + + // Try to apply spawn state (before ready). + if (pending_buffer_size > 0) { + ERR_FAIL_COND_V(!node || sync->get_replication_config().is_null(), ERR_UNCONFIGURED); + int consumed = 0; + const List<NodePath> props = sync->get_replication_config()->get_spawn_properties(); + Vector<Variant> vars; + vars.resize(props.size()); + Error err = MultiplayerAPI::decode_and_decompress_variants(vars, pending_buffer, pending_buffer_size, consumed); + ERR_FAIL_COND_V(err, err); + if (consumed > 0) { + pending_buffer += consumed; + pending_buffer_size -= consumed; + err = MultiplayerSynchronizer::set_state(props, node, vars); + ERR_FAIL_COND_V(err, err); + } + } } return OK; } @@ -154,59 +222,98 @@ Error SceneReplicationInterface::on_replication_stop(Object *p_obj, Variant p_co MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER); sync->disconnect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed)); - return rep_state->config_del_sync(node, sync); + // Untrack synchronizer. + const ObjectID oid = node->get_instance_id(); + const ObjectID sid = sync->get_instance_id(); + ERR_FAIL_COND_V(!tracked_nodes.has(oid), ERR_INVALID_PARAMETER); + TrackedNode &tobj = _track(oid); + tobj.synchronizers.erase(sid); + sync_nodes.erase(sid); + for (KeyValue<int, PeerInfo> &E : peers_info) { + E.value.sync_nodes.erase(sid); + if (sync->get_net_id()) { + E.value.recv_sync_ids.erase(sync->get_net_id()); + } + } + return OK; } -void SceneReplicationInterface::_visibility_changed(int p_peer, ObjectID p_oid) { - if (rep_state->is_spawned_node(p_oid)) { - _update_spawn_visibility(p_peer, p_oid); - } - if (rep_state->is_synced_node(p_oid)) { - _update_sync_visibility(p_peer, p_oid); +void SceneReplicationInterface::_visibility_changed(int p_peer, ObjectID p_sid) { + MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(p_sid); + ERR_FAIL_COND(!sync); // Bug. + Node *node = sync->get_root_node(); + ERR_FAIL_COND(!node); // Bug. + const ObjectID oid = node->get_instance_id(); + if (spawned_nodes.has(oid)) { + _update_spawn_visibility(p_peer, oid); } + _update_sync_visibility(p_peer, sync); } -Error SceneReplicationInterface::_update_sync_visibility(int p_peer, const ObjectID &p_oid) { - MultiplayerSynchronizer *sync = rep_state->get_synchronizer(p_oid); - ERR_FAIL_COND_V(!sync || !sync->is_multiplayer_authority(), ERR_BUG); - bool is_visible = sync->is_visible_to(p_peer); +Error SceneReplicationInterface::_update_sync_visibility(int p_peer, MultiplayerSynchronizer *p_sync) { + ERR_FAIL_COND_V(!p_sync, ERR_BUG); + if (!multiplayer->has_multiplayer_peer() || !p_sync->is_multiplayer_authority()) { + return OK; + } + + const ObjectID &sid = p_sync->get_instance_id(); + bool is_visible = p_sync->is_visible_to(p_peer); if (p_peer == 0) { - for (int pid : rep_state->get_peers()) { + for (KeyValue<int, PeerInfo> &E : peers_info) { // Might be visible to this specific peer. - is_visible = is_visible || sync->is_visible_to(pid); - if (rep_state->is_peer_sync(pid, p_oid) == is_visible) { + is_visible = is_visible || p_sync->is_visible_to(E.key); + if (is_visible == E.value.sync_nodes.has(sid)) { continue; } if (is_visible) { - rep_state->peer_add_sync(pid, p_oid); + E.value.sync_nodes.insert(sid); } else { - rep_state->peer_del_sync(pid, p_oid); + E.value.sync_nodes.erase(sid); } } return OK; } else { - if (is_visible == rep_state->is_peer_sync(p_peer, p_oid)) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + if (is_visible == peers_info[p_peer].sync_nodes.has(sid)) { return OK; } if (is_visible) { - return rep_state->peer_add_sync(p_peer, p_oid); + peers_info[p_peer].sync_nodes.insert(sid); } else { - return rep_state->peer_del_sync(p_peer, p_oid); + peers_info[p_peer].sync_nodes.erase(sid); } + return OK; } } Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const ObjectID &p_oid) { - MultiplayerSpawner *spawner = rep_state->get_spawner(p_oid); - MultiplayerSynchronizer *sync = rep_state->get_synchronizer(p_oid); - Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_oid)); + const TrackedNode *tnode = tracked_nodes.getptr(p_oid); + ERR_FAIL_COND_V(!tnode, ERR_BUG); + MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tnode->spawner); + Node *node = get_id_as<Node>(p_oid); ERR_FAIL_COND_V(!node || !spawner || !spawner->is_multiplayer_authority(), ERR_BUG); - bool is_visible = !sync || sync->is_visible_to(p_peer); + ERR_FAIL_COND_V(!tracked_nodes.has(p_oid), ERR_BUG); + const HashSet<ObjectID> synchronizers = tracked_nodes[p_oid].synchronizers; + bool is_visible = true; + for (const ObjectID &sid : synchronizers) { + MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid); + ERR_CONTINUE(!sync); + if (!sync->is_multiplayer_authority()) { + continue; + } + // Spawn visibility is composed using OR when multiple synchronizers are present. + if (sync->is_visible_to(p_peer)) { + is_visible = true; + break; + } + is_visible = false; + } // Spawn (and despawn) when needed. HashSet<int> to_spawn; HashSet<int> to_despawn; if (p_peer) { - if (is_visible == rep_state->is_peer_spawn(p_peer, p_oid)) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + if (is_visible == peers_info[p_peer].spawn_nodes.has(p_oid)) { return OK; } if (is_visible) { @@ -216,33 +323,37 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje } } else { // Check visibility for each peers. - for (int pid : rep_state->get_peers()) { - bool peer_visible = is_visible || sync->is_visible_to(pid); - if (peer_visible == rep_state->is_peer_spawn(pid, p_oid)) { - continue; - } - if (peer_visible) { - to_spawn.insert(pid); + for (const KeyValue<int, PeerInfo> &E : peers_info) { + if (is_visible) { + // This is fast, since the the object is visibile to everyone, we don't need to check each peer. + if (E.value.spawn_nodes.has(p_oid)) { + // Already spawned. + continue; + } + to_spawn.insert(E.key); } else { - to_despawn.insert(pid); + // Need to check visibility for each peer. + _update_spawn_visibility(E.key, p_oid); } } } if (to_spawn.size()) { int len = 0; - _make_spawn_packet(node, len); + _make_spawn_packet(node, spawner, len); for (int pid : to_spawn) { + ERR_CONTINUE(!peers_info.has(pid)); int path_id; multiplayer->get_path_cache()->send_object_cache(spawner, pid, path_id); _send_raw(packet_cache.ptr(), len, pid, true); - rep_state->peer_add_spawn(pid, p_oid); + peers_info[pid].spawn_nodes.insert(p_oid); } } if (to_despawn.size()) { int len = 0; _make_despawn_packet(node, len); for (int pid : to_despawn) { - rep_state->peer_del_spawn(pid, p_oid); + ERR_CONTINUE(!peers_info.has(pid)); + peers_info[pid].spawn_nodes.erase(p_oid); _send_raw(packet_cache.ptr(), len, pid, true); } } @@ -265,20 +376,20 @@ Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, return peer->put_packet(p_buffer, p_size); } -Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, int &r_len) { - ERR_FAIL_COND_V(!multiplayer, ERR_BUG); +Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len) { + ERR_FAIL_COND_V(!multiplayer || !p_node || !p_spawner, ERR_BUG); const ObjectID oid = p_node->get_instance_id(); - MultiplayerSpawner *spawner = rep_state->get_spawner(oid); - ERR_FAIL_COND_V(!spawner || !p_node, ERR_BUG); + const TrackedNode *tnode = tracked_nodes.getptr(oid); + ERR_FAIL_COND_V(!tnode, ERR_INVALID_PARAMETER); - uint32_t nid = rep_state->get_net_id(oid); + uint32_t nid = tnode->net_id; ERR_FAIL_COND_V(!nid, ERR_UNCONFIGURED); // Prepare custom arg and scene_id - uint8_t scene_id = spawner->find_spawnable_scene_index_from_object(oid); + uint8_t scene_id = p_spawner->find_spawnable_scene_index_from_object(oid); bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID; - Variant spawn_arg = spawner->get_spawn_argument(oid); + Variant spawn_arg = p_spawner->get_spawn_argument(oid); int spawn_arg_size = 0; if (is_custom) { Error err = MultiplayerAPI::encode_and_compress_variant(spawn_arg, nullptr, spawn_arg_size, false); @@ -286,31 +397,51 @@ Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, int &r_len) { } // Prepare spawn state. + List<NodePath> state_props; + List<uint32_t> sync_ids; + const HashSet<ObjectID> synchronizers = tnode->synchronizers; + for (const ObjectID &sid : synchronizers) { + MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid); + if (!sync->is_multiplayer_authority()) { + continue; + } + ERR_CONTINUE(!sync); + ERR_FAIL_COND_V(sync->get_replication_config().is_null(), ERR_BUG); + for (const NodePath &prop : sync->get_replication_config()->get_spawn_properties()) { + state_props.push_back(prop); + } + // Ensure the synchronizer has an ID. + if (sync->get_net_id() == 0) { + sync->set_net_id(++last_net_id); + } + sync_ids.push_back(sync->get_net_id()); + } int state_size = 0; Vector<Variant> state_vars; Vector<const Variant *> state_varp; - MultiplayerSynchronizer *synchronizer = rep_state->get_synchronizer(oid); - if (synchronizer) { - ERR_FAIL_COND_V(synchronizer->get_replication_config().is_null(), ERR_BUG); - const List<NodePath> props = synchronizer->get_replication_config()->get_spawn_properties(); - Error err = MultiplayerSynchronizer::get_state(props, p_node, state_vars, state_varp); + if (state_props.size()) { + Error err = MultiplayerSynchronizer::get_state(state_props, p_node, state_vars, state_varp); ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to retrieve spawn state."); err = MultiplayerAPI::encode_and_compress_variants(state_varp.ptrw(), state_varp.size(), nullptr, state_size); ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to encode spawn state."); } // Encode scene ID, path ID, net ID, node name. - int path_id = multiplayer->get_path_cache()->make_object_cache(spawner); + int path_id = multiplayer->get_path_cache()->make_object_cache(p_spawner); CharString cname = p_node->get_name().operator String().utf8(); int nlen = encode_cstring(cname.get_data(), nullptr); - MAKE_ROOM(1 + 1 + 4 + 4 + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size); + MAKE_ROOM(1 + 1 + 4 + 4 + 4 + 4 * sync_ids.size() + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size); uint8_t *ptr = packet_cache.ptrw(); ptr[0] = (uint8_t)SceneMultiplayer::NETWORK_COMMAND_SPAWN; ptr[1] = scene_id; int ofs = 2; ofs += encode_uint32(path_id, &ptr[ofs]); ofs += encode_uint32(nid, &ptr[ofs]); + ofs += encode_uint32(sync_ids.size(), &ptr[ofs]); ofs += encode_uint32(nlen, &ptr[ofs]); + for (uint32_t snid : sync_ids) { + ofs += encode_uint32(snid, &ptr[ofs]); + } ofs += encode_cstring(cname.get_data(), &ptr[ofs]); // Write args if (is_custom) { @@ -331,18 +462,20 @@ Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, int &r_len) { Error SceneReplicationInterface::_make_despawn_packet(Node *p_node, int &r_len) { const ObjectID oid = p_node->get_instance_id(); + const TrackedNode *tnode = tracked_nodes.getptr(oid); + ERR_FAIL_COND_V(!tnode, ERR_INVALID_PARAMETER); MAKE_ROOM(5); uint8_t *ptr = packet_cache.ptrw(); ptr[0] = (uint8_t)SceneMultiplayer::NETWORK_COMMAND_DESPAWN; int ofs = 1; - uint32_t nid = rep_state->get_net_id(oid); + uint32_t nid = tnode->net_id; ofs += encode_uint32(nid, &ptr[ofs]); r_len = ofs; return OK; } Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) { - ERR_FAIL_COND_V_MSG(p_buffer_len < 14, ERR_INVALID_DATA, "Invalid spawn packet received"); + ERR_FAIL_COND_V_MSG(p_buffer_len < 18, ERR_INVALID_DATA, "Invalid spawn packet received"); int ofs = 1; // The spawn/despawn command. uint8_t scene_id = p_buffer[ofs]; ofs += 1; @@ -354,9 +487,16 @@ Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_b uint32_t net_id = decode_uint32(&p_buffer[ofs]); ofs += 4; + uint32_t sync_len = decode_uint32(&p_buffer[ofs]); + ofs += 4; uint32_t name_len = decode_uint32(&p_buffer[ofs]); ofs += 4; - ERR_FAIL_COND_V_MSG(name_len > uint32_t(p_buffer_len - ofs), ERR_INVALID_DATA, vformat("Invalid spawn packet size: %d, wants: %d", p_buffer_len, ofs + name_len)); + ERR_FAIL_COND_V_MSG(name_len + (sync_len * 4) > uint32_t(p_buffer_len - ofs), ERR_INVALID_DATA, vformat("Invalid spawn packet size: %d, wants: %d", p_buffer_len, ofs + name_len + (sync_len * 4))); + List<uint32_t> sync_ids; + for (uint32_t i = 0; i < sync_len; i++) { + sync_ids.push_back(decode_uint32(&p_buffer[ofs])); + ofs += 4; + } ERR_FAIL_COND_V_MSG(name_len < 1, ERR_INVALID_DATA, "Zero spawn name size."); // We need to make sure no trickery happens here, but we want to allow autogenerated ("@") node names. @@ -387,20 +527,35 @@ Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_b } ERR_FAIL_COND_V(!node, ERR_UNAUTHORIZED); node->set_name(name); - rep_state->peer_add_remote(p_from, net_id, node, spawner); + + // Add and track remote + ERR_FAIL_COND_V(!peers_info.has(p_from), ERR_UNAVAILABLE); + ERR_FAIL_COND_V(peers_info[p_from].recv_nodes.has(net_id), ERR_ALREADY_IN_USE); + ObjectID oid = node->get_instance_id(); + TrackedNode &tobj = _track(oid); + tobj.spawner = spawner->get_instance_id(); + tobj.net_id = net_id; + tobj.remote_peer = p_from; + peers_info[p_from].recv_nodes[net_id] = oid; + // The initial state will be applied during the sync config (i.e. before _ready). - int state_len = p_buffer_len - ofs; - if (state_len) { - pending_spawn = node->get_instance_id(); - pending_buffer = &p_buffer[ofs]; - pending_buffer_size = state_len; - } + pending_spawn = node->get_instance_id(); + pending_spawn_remote = p_from; + pending_buffer_size = p_buffer_len - ofs; + pending_buffer = pending_buffer_size > 0 ? &p_buffer[ofs] : nullptr; + pending_sync_net_ids = sync_ids; + parent->add_child(node); spawner->emit_signal(SNAME("spawned"), node); pending_spawn = ObjectID(); + pending_spawn_remote = 0; pending_buffer = nullptr; pending_buffer_size = 0; + if (pending_sync_net_ids.size()) { + pending_sync_net_ids.clear(); + ERR_FAIL_V(ERR_INVALID_DATA); // Should have been consumed. + } return OK; } @@ -409,12 +564,18 @@ Error SceneReplicationInterface::on_despawn_receive(int p_from, const uint8_t *p int ofs = 1; // The spawn/despawn command. uint32_t net_id = decode_uint32(&p_buffer[ofs]); ofs += 4; - Node *node = nullptr; - Error err = rep_state->peer_del_remote(p_from, net_id, &node); - ERR_FAIL_COND_V(err != OK, err); + + // Untrack remote + ERR_FAIL_COND_V(!peers_info.has(p_from), ERR_UNAUTHORIZED); + PeerInfo &pinfo = peers_info[p_from]; + ERR_FAIL_COND_V(!pinfo.recv_nodes.has(net_id), ERR_UNAUTHORIZED); + Node *node = get_id_as<Node>(pinfo.recv_nodes[net_id]); ERR_FAIL_COND_V(!node, ERR_BUG); + pinfo.recv_nodes.erase(net_id); - MultiplayerSpawner *spawner = rep_state->get_spawner(node->get_instance_id()); + const ObjectID oid = node->get_instance_id(); + ERR_FAIL_COND_V(!tracked_nodes.has(oid), ERR_BUG); + MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tracked_nodes[oid].spawner); ERR_FAIL_COND_V(!spawner, ERR_DOES_NOT_EXIST); ERR_FAIL_COND_V(p_from != spawner->get_multiplayer_authority(), ERR_UNAUTHORIZED); @@ -427,27 +588,24 @@ Error SceneReplicationInterface::on_despawn_receive(int p_from, const uint8_t *p return OK; } -void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { - const HashSet<ObjectID> &to_sync = rep_state->get_peer_sync_nodes(p_peer); - if (to_sync.is_empty()) { - return; - } +void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_msec) { MAKE_ROOM(sync_mtu); uint8_t *ptr = packet_cache.ptrw(); ptr[0] = SceneMultiplayer::NETWORK_COMMAND_SYNC; int ofs = 1; - ofs += encode_uint16(rep_state->peer_sync_next(p_peer), &ptr[1]); + ofs += encode_uint16(p_sync_net_time, &ptr[1]); // Can only send updates for already notified nodes. // This is a lazy implementation, we could optimize much more here with by grouping by replication config. - for (const ObjectID &oid : to_sync) { - if (!rep_state->update_sync_time(oid, p_msec)) { + for (const ObjectID &oid : p_synchronizers) { + MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(oid); + ERR_CONTINUE(!sync || !sync->get_replication_config().is_valid() || !sync->is_multiplayer_authority()); + if (!sync->update_outbound_sync_time(p_msec)) { continue; // nothing to sync. } - MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); - ERR_CONTINUE(!sync || !sync->get_replication_config().is_valid()); - Node *node = rep_state->get_node(oid); + + Node *node = sync->get_root_node(); ERR_CONTINUE(!node); - uint32_t net_id = rep_state->get_net_id(oid); + uint32_t net_id = sync->get_net_id(); if (net_id == 0 || (net_id & 0x80000000)) { int path_id = 0; bool verified = multiplayer->get_path_cache()->send_object_cache(sync, p_peer, path_id); @@ -455,7 +613,7 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { if (net_id == 0) { // First time path based ID. net_id = path_id | 0x80000000; - rep_state->set_net_id(oid, net_id | 0x80000000); + sync->set_net_id(net_id | 0x80000000); } if (!verified) { // The path based sync is not yet confirmed, skipping. @@ -478,7 +636,7 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { ofs = 3; } if (size) { - ofs += encode_uint32(rep_state->get_net_id(oid), &ptr[ofs]); + ofs += encode_uint32(sync->get_net_id(), &ptr[ofs]); ofs += encode_uint32(size, &ptr[ofs]); MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), &ptr[ofs], size); ofs += size; @@ -494,33 +652,32 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu ERR_FAIL_COND_V_MSG(p_buffer_len < 11, ERR_INVALID_DATA, "Invalid sync packet received"); uint16_t time = decode_uint16(&p_buffer[1]); int ofs = 3; - rep_state->peer_sync_recv(p_from, time); while (ofs + 8 < p_buffer_len) { uint32_t net_id = decode_uint32(&p_buffer[ofs]); ofs += 4; uint32_t size = decode_uint32(&p_buffer[ofs]); ofs += 4; - Node *node = nullptr; + MultiplayerSynchronizer *sync = nullptr; if (net_id & 0x80000000) { - MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer->get_path_cache()->get_cached_object(p_from, net_id & 0x7FFFFFFF)); - ERR_FAIL_COND_V(!sync || sync->get_multiplayer_authority() != p_from, ERR_UNAUTHORIZED); - node = sync->get_node(sync->get_root_path()); - } else { - node = rep_state->peer_get_remote(p_from, net_id); + sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer->get_path_cache()->get_cached_object(p_from, net_id & 0x7FFFFFFF)); + } else if (peers_info[p_from].recv_sync_ids.has(net_id)) { + const ObjectID &sid = peers_info[p_from].recv_sync_ids[net_id]; + sync = get_id_as<MultiplayerSynchronizer>(sid); } - if (!node) { + if (!sync) { // Not received yet. ofs += size; continue; } - const ObjectID oid = node->get_instance_id(); - if (!rep_state->update_last_node_sync(oid, time)) { + Node *node = sync->get_root_node(); + if (sync->get_multiplayer_authority() != p_from || !node) { + ERR_CONTINUE(true); + } + if (!sync->update_inbound_sync_time(time)) { // State is too old. ofs += size; continue; } - MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); - ERR_FAIL_COND_V(!sync, ERR_BUG); ERR_FAIL_COND_V(size > uint32_t(p_buffer_len - ofs), ERR_BUG); const List<NodePath> props = sync->get_replication_config()->get_sync_properties(); Vector<Variant> vars; diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h index 8981647429..ee454f604e 100644 --- a/modules/multiplayer/scene_replication_interface.h +++ b/modules/multiplayer/scene_replication_interface.h @@ -31,9 +31,10 @@ #ifndef SCENE_REPLICATION_INTERFACE_H #define SCENE_REPLICATION_INTERFACE_H -#include "scene/main/multiplayer_api.h" +#include "core/object/ref_counted.h" -#include "scene_replication_state.h" +#include "multiplayer_spawner.h" +#include "multiplayer_synchronizer.h" class SceneMultiplayer; @@ -41,25 +42,68 @@ class SceneReplicationInterface : public RefCounted { GDCLASS(SceneReplicationInterface, RefCounted); private: - void _send_sync(int p_peer, uint64_t p_msec); - Error _make_spawn_packet(Node *p_node, int &r_len); - Error _make_despawn_packet(Node *p_node, int &r_len); - Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable); + struct TrackedNode { + ObjectID id; + uint32_t net_id = 0; + uint32_t remote_peer = 0; + ObjectID spawner; + HashSet<ObjectID> synchronizers; - void _visibility_changed(int p_peer, ObjectID p_oid); - Error _update_sync_visibility(int p_peer, const ObjectID &p_oid); - Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid); - void _free_remotes(int p_peer); + bool operator==(const ObjectID &p_other) { return id == p_other; } - Ref<SceneReplicationState> rep_state; - SceneMultiplayer *multiplayer = nullptr; - PackedByteArray packet_cache; - int sync_mtu = 1350; // Highly dependent on underlying protocol. + _FORCE_INLINE_ MultiplayerSpawner *get_spawner() const { return spawner.is_valid() ? Object::cast_to<MultiplayerSpawner>(ObjectDB::get_instance(spawner)) : nullptr; } + TrackedNode() {} + TrackedNode(const ObjectID &p_id) { id = p_id; } + TrackedNode(const ObjectID &p_id, uint32_t p_net_id) { + id = p_id; + net_id = p_net_id; + } + }; + + struct PeerInfo { + HashSet<ObjectID> sync_nodes; + HashSet<ObjectID> spawn_nodes; + HashMap<uint32_t, ObjectID> recv_sync_ids; + HashMap<uint32_t, ObjectID> recv_nodes; + uint16_t last_sent_sync = 0; + }; + + // Replication state. + HashMap<int, PeerInfo> peers_info; + uint32_t last_net_id = 0; + HashMap<ObjectID, TrackedNode> tracked_nodes; + HashSet<ObjectID> spawned_nodes; + HashSet<ObjectID> sync_nodes; - // An hack to apply the initial state before ready. + // Pending spawn informations. ObjectID pending_spawn; + int pending_spawn_remote = 0; const uint8_t *pending_buffer = nullptr; int pending_buffer_size = 0; + List<uint32_t> pending_sync_net_ids; + + // Replicator config. + SceneMultiplayer *multiplayer = nullptr; + PackedByteArray packet_cache; + int sync_mtu = 1350; // Highly dependent on underlying protocol. + + TrackedNode &_track(const ObjectID &p_id); + void _untrack(const ObjectID &p_id); + + void _send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_msec); + Error _make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len); + Error _make_despawn_packet(Node *p_node, int &r_len); + Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable); + + void _visibility_changed(int p_peer, ObjectID p_oid); + Error _update_sync_visibility(int p_peer, MultiplayerSynchronizer *p_sync); + Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid); + void _free_remotes(const PeerInfo &p_info); + + template <class T> + static T *get_id_as(const ObjectID &p_id) { + return p_id.is_valid() ? Object::cast_to<T>(ObjectDB::get_instance(p_id)) : nullptr; + } public: static void make_default(); @@ -78,7 +122,6 @@ public: Error on_sync_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len); SceneReplicationInterface(SceneMultiplayer *p_multiplayer) { - rep_state.instantiate(); multiplayer = p_multiplayer; } }; diff --git a/modules/multiplayer/scene_replication_state.cpp b/modules/multiplayer/scene_replication_state.cpp deleted file mode 100644 index fbcf0acadb..0000000000 --- a/modules/multiplayer/scene_replication_state.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/*************************************************************************/ -/* scene_replication_state.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 "scene_replication_state.h" - -#include "scene/scene_string_names.h" - -#include "multiplayer_spawner.h" -#include "multiplayer_synchronizer.h" - -SceneReplicationState::TrackedNode &SceneReplicationState::_track(const ObjectID &p_id) { - if (!tracked_nodes.has(p_id)) { - tracked_nodes[p_id] = TrackedNode(p_id); - Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id)); - node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack).bind(p_id), Node::CONNECT_ONE_SHOT); - } - return tracked_nodes[p_id]; -} - -void SceneReplicationState::_untrack(const ObjectID &p_id) { - if (tracked_nodes.has(p_id)) { - uint32_t net_id = tracked_nodes[p_id].net_id; - uint32_t peer = tracked_nodes[p_id].remote_peer; - tracked_nodes.erase(p_id); - // If it was spawned by a remote, remove it from the received nodes. - if (peer && peers_info.has(peer)) { - peers_info[peer].recv_nodes.erase(net_id); - } - // If we spawned or synced it, we need to remove it from any peer it was sent to. - if (net_id || peer == 0) { - for (KeyValue<int, PeerInfo> &E : peers_info) { - E.value.sync_nodes.erase(p_id); - E.value.spawn_nodes.erase(p_id); - } - } - } -} - -const HashMap<uint32_t, ObjectID> SceneReplicationState::peer_get_remotes(int p_peer) const { - return peers_info.has(p_peer) ? peers_info[p_peer].recv_nodes : HashMap<uint32_t, ObjectID>(); -} - -bool SceneReplicationState::update_last_node_sync(const ObjectID &p_id, uint16_t p_time) { - TrackedNode *tnode = tracked_nodes.getptr(p_id); - ERR_FAIL_COND_V(!tnode, false); - if (p_time <= tnode->last_sync && tnode->last_sync - p_time < 32767) { - return false; - } - tnode->last_sync = p_time; - return true; -} - -bool SceneReplicationState::update_sync_time(const ObjectID &p_id, uint64_t p_msec) { - TrackedNode *tnode = tracked_nodes.getptr(p_id); - ERR_FAIL_COND_V(!tnode, false); - MultiplayerSynchronizer *sync = get_synchronizer(p_id); - if (!sync) { - return false; - } - if (tnode->last_sync_msec == p_msec) { - return true; - } - if (p_msec >= tnode->last_sync_msec + sync->get_replication_interval_msec()) { - tnode->last_sync_msec = p_msec; - return true; - } - return false; -} - -uint32_t SceneReplicationState::get_net_id(const ObjectID &p_id) const { - const TrackedNode *tnode = tracked_nodes.getptr(p_id); - ERR_FAIL_COND_V(!tnode, 0); - return tnode->net_id; -} - -void SceneReplicationState::set_net_id(const ObjectID &p_id, uint32_t p_net_id) { - TrackedNode *tnode = tracked_nodes.getptr(p_id); - ERR_FAIL_COND(!tnode); - tnode->net_id = p_net_id; -} - -uint32_t SceneReplicationState::ensure_net_id(const ObjectID &p_id) { - TrackedNode *tnode = tracked_nodes.getptr(p_id); - ERR_FAIL_COND_V(!tnode, 0); - if (tnode->net_id == 0) { - tnode->net_id = ++last_net_id; - } - return tnode->net_id; -} - -void SceneReplicationState::on_peer_change(int p_peer, bool p_connected) { - if (p_connected) { - peers_info[p_peer] = PeerInfo(); - known_peers.insert(p_peer); - } else { - peers_info.erase(p_peer); - known_peers.erase(p_peer); - } -} - -void SceneReplicationState::reset() { - peers_info.clear(); - known_peers.clear(); - // Tracked nodes are cleared on deletion, here we only reset the ids so they can be later re-assigned. - for (KeyValue<ObjectID, TrackedNode> &E : tracked_nodes) { - TrackedNode &tobj = E.value; - tobj.net_id = 0; - tobj.remote_peer = 0; - tobj.last_sync = 0; - } -} - -Error SceneReplicationState::config_add_spawn(Node *p_node, MultiplayerSpawner *p_spawner) { - const ObjectID oid = p_node->get_instance_id(); - TrackedNode &tobj = _track(oid); - ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); - tobj.spawner = p_spawner->get_instance_id(); - spawned_nodes.insert(oid); - return OK; -} - -Error SceneReplicationState::config_del_spawn(Node *p_node, MultiplayerSpawner *p_spawner) { - const ObjectID oid = p_node->get_instance_id(); - ERR_FAIL_COND_V(!is_tracked(oid), ERR_INVALID_PARAMETER); - TrackedNode &tobj = _track(oid); - ERR_FAIL_COND_V(tobj.spawner != p_spawner->get_instance_id(), ERR_INVALID_PARAMETER); - tobj.spawner = ObjectID(); - spawned_nodes.erase(oid); - for (KeyValue<int, PeerInfo> &E : peers_info) { - E.value.spawn_nodes.erase(oid); - } - return OK; -} - -Error SceneReplicationState::config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync) { - const ObjectID oid = p_node->get_instance_id(); - TrackedNode &tobj = _track(oid); - ERR_FAIL_COND_V(tobj.synchronizer != ObjectID(), ERR_ALREADY_IN_USE); - tobj.synchronizer = p_sync->get_instance_id(); - synced_nodes.insert(oid); - return OK; -} - -Error SceneReplicationState::config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync) { - const ObjectID oid = p_node->get_instance_id(); - ERR_FAIL_COND_V(!is_tracked(oid), ERR_INVALID_PARAMETER); - TrackedNode &tobj = _track(oid); - ERR_FAIL_COND_V(tobj.synchronizer != p_sync->get_instance_id(), ERR_INVALID_PARAMETER); - tobj.synchronizer = ObjectID(); - synced_nodes.erase(oid); - for (KeyValue<int, PeerInfo> &E : peers_info) { - E.value.sync_nodes.erase(oid); - } - return OK; -} - -Error SceneReplicationState::peer_add_sync(int p_peer, const ObjectID &p_id) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); - peers_info[p_peer].sync_nodes.insert(p_id); - return OK; -} - -Error SceneReplicationState::peer_del_sync(int p_peer, const ObjectID &p_id) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); - peers_info[p_peer].sync_nodes.erase(p_id); - return OK; -} - -const HashSet<ObjectID> SceneReplicationState::get_peer_sync_nodes(int p_peer) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>()); - return peers_info[p_peer].sync_nodes; -} - -bool SceneReplicationState::is_peer_sync(int p_peer, const ObjectID &p_id) const { - ERR_FAIL_COND_V(!peers_info.has(p_peer), false); - return peers_info[p_peer].sync_nodes.has(p_id); -} - -Error SceneReplicationState::peer_add_spawn(int p_peer, const ObjectID &p_id) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); - peers_info[p_peer].spawn_nodes.insert(p_id); - return OK; -} - -Error SceneReplicationState::peer_del_spawn(int p_peer, const ObjectID &p_id) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); - peers_info[p_peer].spawn_nodes.erase(p_id); - return OK; -} - -const HashSet<ObjectID> SceneReplicationState::get_peer_spawn_nodes(int p_peer) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>()); - return peers_info[p_peer].spawn_nodes; -} - -bool SceneReplicationState::is_peer_spawn(int p_peer, const ObjectID &p_id) const { - ERR_FAIL_COND_V(!peers_info.has(p_peer), false); - return peers_info[p_peer].spawn_nodes.has(p_id); -} - -Node *SceneReplicationState::peer_get_remote(int p_peer, uint32_t p_net_id) { - PeerInfo *info = peers_info.getptr(p_peer); - return info && info->recv_nodes.has(p_net_id) ? Object::cast_to<Node>(ObjectDB::get_instance(info->recv_nodes[p_net_id])) : nullptr; -} - -Error SceneReplicationState::peer_add_remote(int p_peer, uint32_t p_net_id, Node *p_node, MultiplayerSpawner *p_spawner) { - ERR_FAIL_COND_V(!p_node || !p_spawner, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_UNAVAILABLE); - PeerInfo &pinfo = peers_info[p_peer]; - ObjectID oid = p_node->get_instance_id(); - TrackedNode &tobj = _track(oid); - tobj.spawner = p_spawner->get_instance_id(); - tobj.net_id = p_net_id; - tobj.remote_peer = p_peer; - tobj.last_sync = pinfo.last_recv_sync; - // Also track as a remote. - ERR_FAIL_COND_V(pinfo.recv_nodes.has(p_net_id), ERR_ALREADY_IN_USE); - pinfo.recv_nodes[p_net_id] = oid; - return OK; -} - -Error SceneReplicationState::peer_del_remote(int p_peer, uint32_t p_net_id, Node **r_node) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_UNAUTHORIZED); - PeerInfo &info = peers_info[p_peer]; - ERR_FAIL_COND_V(!info.recv_nodes.has(p_net_id), ERR_UNAUTHORIZED); - *r_node = Object::cast_to<Node>(ObjectDB::get_instance(info.recv_nodes[p_net_id])); - info.recv_nodes.erase(p_net_id); - return OK; -} - -uint16_t SceneReplicationState::peer_sync_next(int p_peer) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), 0); - PeerInfo &info = peers_info[p_peer]; - return ++info.last_sent_sync; -} - -void SceneReplicationState::peer_sync_recv(int p_peer, uint16_t p_time) { - ERR_FAIL_COND(!peers_info.has(p_peer)); - peers_info[p_peer].last_recv_sync = p_time; -} diff --git a/modules/multiplayer/scene_replication_state.h b/modules/multiplayer/scene_replication_state.h deleted file mode 100644 index bdff6ae3b7..0000000000 --- a/modules/multiplayer/scene_replication_state.h +++ /dev/null @@ -1,135 +0,0 @@ -/*************************************************************************/ -/* scene_replication_state.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 SCENE_REPLICATION_STATE_H -#define SCENE_REPLICATION_STATE_H - -#include "core/object/ref_counted.h" - -#include "multiplayer_spawner.h" -#include "multiplayer_synchronizer.h" - -class MultiplayerSpawner; -class MultiplayerSynchronizer; -class Node; - -class SceneReplicationState : public RefCounted { -private: - struct TrackedNode { - ObjectID id; - uint32_t net_id = 0; - uint32_t remote_peer = 0; - ObjectID spawner; - ObjectID synchronizer; - uint16_t last_sync = 0; - uint64_t last_sync_msec = 0; - - bool operator==(const ObjectID &p_other) { return id == p_other; } - - Node *get_node() const { return id.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(id)) : nullptr; } - MultiplayerSpawner *get_spawner() const { return spawner.is_valid() ? Object::cast_to<MultiplayerSpawner>(ObjectDB::get_instance(spawner)) : nullptr; } - MultiplayerSynchronizer *get_synchronizer() const { return synchronizer.is_valid() ? Object::cast_to<MultiplayerSynchronizer>(ObjectDB::get_instance(synchronizer)) : nullptr; } - TrackedNode() {} - TrackedNode(const ObjectID &p_id) { id = p_id; } - TrackedNode(const ObjectID &p_id, uint32_t p_net_id) { - id = p_id; - net_id = p_net_id; - } - }; - - struct PeerInfo { - HashSet<ObjectID> sync_nodes; - HashSet<ObjectID> spawn_nodes; - HashMap<uint32_t, ObjectID> recv_nodes; - uint16_t last_sent_sync = 0; - uint16_t last_recv_sync = 0; - }; - - HashSet<int> known_peers; - uint32_t last_net_id = 0; - HashMap<ObjectID, TrackedNode> tracked_nodes; - HashMap<int, PeerInfo> peers_info; - HashSet<ObjectID> spawned_nodes; - HashSet<ObjectID> synced_nodes; - - TrackedNode &_track(const ObjectID &p_id); - void _untrack(const ObjectID &p_id); - bool is_tracked(const ObjectID &p_id) const { return tracked_nodes.has(p_id); } - -public: - const HashSet<int> get_peers() const { return known_peers; } - const HashSet<ObjectID> &get_spawned_nodes() const { return spawned_nodes; } - bool is_spawned_node(const ObjectID &p_id) const { return spawned_nodes.has(p_id); } - const HashSet<ObjectID> &get_synced_nodes() const { return synced_nodes; } - bool is_synced_node(const ObjectID &p_id) const { return synced_nodes.has(p_id); } - - MultiplayerSynchronizer *get_synchronizer(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_synchronizer() : nullptr; } - MultiplayerSpawner *get_spawner(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_spawner() : nullptr; } - Node *get_node(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_node() : nullptr; } - bool update_last_node_sync(const ObjectID &p_id, uint16_t p_time); - bool update_sync_time(const ObjectID &p_id, uint64_t p_msec); - - uint32_t get_net_id(const ObjectID &p_id) const; - void set_net_id(const ObjectID &p_id, uint32_t p_net_id); - uint32_t ensure_net_id(const ObjectID &p_id); - - void reset(); - void on_peer_change(int p_peer, bool p_connected); - - Error config_add_spawn(Node *p_node, MultiplayerSpawner *p_spawner); - Error config_del_spawn(Node *p_node, MultiplayerSpawner *p_spawner); - - Error config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync); - Error config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync); - - Error peer_add_sync(int p_peer, const ObjectID &p_id); - Error peer_del_sync(int p_peer, const ObjectID &p_id); - - const HashSet<ObjectID> get_peer_sync_nodes(int p_peer); - bool is_peer_sync(int p_peer, const ObjectID &p_id) const; - - Error peer_add_spawn(int p_peer, const ObjectID &p_id); - Error peer_del_spawn(int p_peer, const ObjectID &p_id); - - const HashSet<ObjectID> get_peer_spawn_nodes(int p_peer); - bool is_peer_spawn(int p_peer, const ObjectID &p_id) const; - - const HashMap<uint32_t, ObjectID> peer_get_remotes(int p_peer) const; - Node *peer_get_remote(int p_peer, uint32_t p_net_id); - Error peer_add_remote(int p_peer, uint32_t p_net_id, Node *p_node, MultiplayerSpawner *p_spawner); - Error peer_del_remote(int p_peer, uint32_t p_net_id, Node **r_node); - - uint16_t peer_sync_next(int p_peer); - void peer_sync_recv(int p_peer, uint16_t p_time); - - SceneReplicationState() {} -}; - -#endif // SCENE_REPLICATION_STATE_H diff --git a/modules/navigation/SCsub b/modules/navigation/SCsub index 24a6b12639..0b0822db2d 100644 --- a/modules/navigation/SCsub +++ b/modules/navigation/SCsub @@ -57,7 +57,7 @@ env.modules_sources += thirdparty_obj module_obj = [] env_navigation.add_source_files(module_obj, "*.cpp") -if env["tools"]: +if env.editor_build: env_navigation.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 100db9bc82..83862e1e34 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -140,20 +140,17 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p // This is an implementation of the A* algorithm. int least_cost_id = 0; + int prev_least_cost_id = -1; bool found_route = false; const gd::Polygon *reachable_end = nullptr; float reachable_d = 1e30; bool is_reachable = true; - gd::NavigationPoly *prev_least_cost_poly = nullptr; - while (true) { // Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance. for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) { - gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id]; - - const gd::Edge &edge = least_cost_poly->poly->edges[i]; + const gd::Edge &edge = navigation_polys[least_cost_id].poly->edges[i]; // Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon. for (int connection_index = 0; connection_index < edge.connections.size(); connection_index++) { @@ -164,17 +161,18 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p continue; } + const gd::NavigationPoly &least_cost_poly = navigation_polys[least_cost_id]; float poly_enter_cost = 0.0; - float poly_travel_cost = least_cost_poly->poly->owner->get_travel_cost(); + float poly_travel_cost = least_cost_poly.poly->owner->get_travel_cost(); - if (prev_least_cost_poly != nullptr && (prev_least_cost_poly->poly->owner->get_self() != least_cost_poly->poly->owner->get_self())) { - poly_enter_cost = least_cost_poly->poly->owner->get_enter_cost(); + if (prev_least_cost_id != -1 && (navigation_polys[prev_least_cost_id].poly->owner->get_self() != least_cost_poly.poly->owner->get_self())) { + poly_enter_cost = least_cost_poly.poly->owner->get_enter_cost(); } - prev_least_cost_poly = least_cost_poly; + prev_least_cost_id = least_cost_id; Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end }; - const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway); - const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly->traveled_distance; + const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly.entry, pathway); + const float new_distance = (least_cost_poly.entry.distance_to(new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly.traveled_distance; int64_t already_visited_polygon_index = navigation_polys.find(gd::NavigationPoly(connection.polygon)); @@ -240,6 +238,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p to_visit.clear(); to_visit.push_back(0); least_cost_id = 0; + prev_least_cost_id = -1; reachable_end = nullptr; diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp index 8d279f9dd3..101a66371b 100644 --- a/modules/noise/noise_texture_2d.cpp +++ b/modules/noise/noise_texture_2d.cpp @@ -197,9 +197,6 @@ void NoiseTexture2D::_update_texture() { use_thread = false; first_time = false; } -#ifdef NO_THREADS - use_thread = false; -#endif if (use_thread) { if (!noise_thread.is_started()) { noise_thread.start(_thread_function, this); diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 593d1ff3c1..d4469b110b 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -18,38 +18,36 @@ env_openxr.Prepend( thirdparty_dir + "/src", thirdparty_dir + "/src/common", thirdparty_dir + "/src/external/jsoncpp/include", - thirdparty_dir + "/src/loader", ] ) -# may need to check and set: -# - XR_USE_TIMESPEC - -env_thirdparty = env_openxr.Clone() -env_thirdparty.disable_warnings() -env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"]) - if env["platform"] == "android": # may need to set OPENXR_ANDROID_VERSION_SUFFIX - env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"]) + env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"]) + env_openxr.AppendUnique(CPPDEFINES=["JSON_USE_EXCEPTION=0"]) # may need to include java parts of the openxr loader elif env["platform"] == "linuxbsd": - env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX"]) + env_openxr.AppendUnique(CPPDEFINES=["XR_OS_LINUX"]) if env["x11"]: - env_thirdparty.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"]) + env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"]) # FIXME: Review what needs to be set for Android and macOS. - env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) + env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) elif env["platform"] == "windows": - env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"]) + env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"]) -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") +# may need to check and set: +# - XR_USE_TIMESPEC -# add in common files (hope these don't clash with us) -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/object_info.cpp") +env_thirdparty = env_openxr.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"]) + +if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]: + env_thirdparty["CXXFLAGS"].remove("-fno-exceptions") +env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"]) # add in external jsoncpp dependency env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp") @@ -57,17 +55,24 @@ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp") # add in load -if env["platform"] == "android": - env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/android_utilities.cpp") - -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_core.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_instance.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp") +if env["platform"] != "android": + # On Android the openxr_loader is provided by separate plugins for each device + # Build the engine using object files + khrloader_obj = [] + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") + + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp") + + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp") + env.modules_sources += khrloader_obj env.modules_sources += thirdparty_obj @@ -78,6 +83,7 @@ module_obj = [] env_openxr.add_source_files(module_obj, "*.cpp") env_openxr.add_source_files(module_obj, "action_map/*.cpp") +env_openxr.add_source_files(module_obj, "scene/*.cpp") # We're a little more targeted with our extensions if env["platform"] == "android": @@ -85,11 +91,14 @@ if env["platform"] == "android": if env["vulkan"]: env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp") env.modules_sources += module_obj -if env["tools"]: +if env.editor_build: SConscript("editor/SCsub") # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index 0eb5302442..185e44c29d 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -157,7 +157,11 @@ void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p } void OpenXRActionMap::create_default_action_sets() { - // Note, if you make changes here make sure to delete your default_action_map.tres file of it will load an old version. + // Note: + // - if you make changes here make sure to delete your default_action_map.tres file of it will load an old version. + // - our palm pose is only available if the relevant extension is supported, + // we still want it to be part of our action map as we may deploy the same game to platforms that do and don't support it. + // - the same applies for interaction profiles that are only supported if the relevant extension is supported. // Create our Godot action set Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set"); @@ -200,6 +204,7 @@ void OpenXRActionMap::create_default_action_sets() { "/user/vive_tracker_htcx/role/keyboard"); Ref<OpenXRAction> aim_pose = action_set->add_new_action("aim_pose", "Aim pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> grip_pose = action_set->add_new_action("grip_pose", "Grip pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); + Ref<OpenXRAction> palm_pose = action_set->add_new_action("palm_pose", "Palm pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right"); Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC, "/user/hand/left," "/user/hand/right," @@ -222,6 +227,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click"); // generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs @@ -233,6 +239,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); // wmr controller has no a/b/x/y buttons @@ -253,6 +260,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); // wmr 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"); // wmr controller has no a/b/x/y buttons @@ -275,6 +283,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); // touch controllers have no select button we can use profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available 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 @@ -299,6 +308,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); // index controllers have no select button we can use profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers @@ -321,16 +331,12 @@ 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); - // 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"); + profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/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 @@ -353,6 +359,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/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 @@ -375,6 +382,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/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 @@ -398,6 +406,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/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 @@ -421,6 +430,7 @@ void OpenXRActionMap::create_default_action_sets() { 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(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/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"); diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp index 89860199be..59ce829f1b 100644 --- a/modules/openxr/action_map/openxr_defs.cpp +++ b/modules/openxr/action_map/openxr_defs.cpp @@ -62,6 +62,8 @@ OpenXRDefs::IOPath OpenXRDefs::simple_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -78,6 +80,8 @@ OpenXRDefs::IOPath OpenXRDefs::vive_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -109,6 +113,8 @@ OpenXRDefs::IOPath OpenXRDefs::motion_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -143,6 +149,8 @@ OpenXRDefs::IOPath OpenXRDefs::hpmr_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -175,6 +183,8 @@ OpenXRDefs::IOPath OpenXRDefs::touch_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -213,6 +223,8 @@ OpenXRDefs::IOPath OpenXRDefs::index_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -260,6 +272,8 @@ OpenXRDefs::IOPath OpenXRDefs::odyssey_io_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -294,6 +308,8 @@ OpenXRDefs::IOPath OpenXRDefs::vive_cosmos_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -331,6 +347,8 @@ OpenXRDefs::IOPath OpenXRDefs::vive_focus3_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, @@ -371,6 +389,8 @@ OpenXRDefs::IOPath OpenXRDefs::huawei_controller_paths[] = { { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Palm pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/palm_ext/pose", OpenXRAction::OPENXR_ACTION_POSE }, { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL }, { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL }, diff --git a/modules/openxr/config.py b/modules/openxr/config.py index f91cb1359f..279168cc59 100644 --- a/modules/openxr/config.py +++ b/modules/openxr/config.py @@ -1,7 +1,5 @@ def can_build(env, platform): - if ( - platform == "linuxbsd" or platform == "windows" - ): # or platform == "android" -- temporarily disabled android support + if platform in ("linuxbsd", "windows", "android"): return env["openxr"] else: # not supported on these platforms @@ -20,6 +18,7 @@ def get_doc_classes(): "OpenXRActionMap", "OpenXRInteractionProfile", "OpenXRIPBinding", + "OpenXRHand", ] diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml new file mode 100644 index 0000000000..5d5f8a6126 --- /dev/null +++ b/modules/openxr/doc_classes/OpenXRHand.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OpenXRHand" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Node supporting finger tracking in OpenXR. + </brief_description> + <description> + This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to where the player's actual hand is positioned. This node also updates the skeleton of a properly skinned hand model. The hand mesh should be a child node of this node. + </description> + <tutorials> + </tutorials> + <members> + <member name="hand" type="int" setter="set_hand" getter="get_hand" enum="OpenXRHand.Hands" default="0"> + Specifies whether this node tracks the left or right hand of the player. + </member> + <member name="hand_skeleton" type="NodePath" setter="set_hand_skeleton" getter="get_hand_skeleton" default="NodePath("")"> + Set a [Skeleton3D] node for which the pose positions will be updated. + </member> + <member name="motion_range" type="int" setter="set_motion_range" getter="get_motion_range" enum="OpenXRHand.MotionRange" default="0"> + Set the motion range (if supported) limiting the hand motion. + </member> + </members> + <constants> + <constant name="HAND_LEFT" value="0" enum="Hands"> + Tracking the player's left hand. + </constant> + <constant name="HAND_RIGHT" value="1" enum="Hands"> + Tracking the player's right hand. + </constant> + <constant name="HAND_MAX" value="2" enum="Hands"> + Maximum supported hands. + </constant> + <constant name="MOTION_RANGE_UNOBSTRUCTED" value="0" enum="MotionRange"> + When player grips, hand skeleton will form a full fist. + </constant> + <constant name="MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="MotionRange"> + When player grips, hand skeleton conforms to the controller the player is holding. + </constant> + <constant name="MOTION_RANGE_MAX" value="2" enum="MotionRange"> + Maximum supported motion ranges. + </constant> + </constants> +</class> diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp index 3bd4db169c..8f6d5c28db 100644 --- a/modules/openxr/extensions/openxr_android_extension.cpp +++ b/modules/openxr/extensions/openxr_android_extension.cpp @@ -29,7 +29,12 @@ /*************************************************************************/ #include "openxr_android_extension.h" +#include "java_godot_wrapper.h" +#include "os_android.h" +#include "thread_jandroid.h" +#include <jni.h> +#include <modules/openxr/openxr_api.h> #include <openxr/openxr.h> #include <openxr/openxr_platform.h> @@ -42,19 +47,16 @@ OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() { OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : OpenXRExtensionWrapper(p_openxr_api) { singleton = this; - request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available +} - // Initialize the loader - PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR; - result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction *)(&xrInitializeLoaderKHR)); - ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to retrieve pointer to xrInitializeLoaderKHR"); +void OpenXRAndroidExtension::on_before_instance_created() { + EXT_INIT_XR_FUNC(xrInitializeLoaderKHR); - // TODO fix this code, this is still code from GDNative! - JNIEnv *env = android_api->godot_android_get_env(); + JNIEnv *env = get_jni_env(); JavaVM *vm; env->GetJavaVM(&vm); - jobject activity_object = env->NewGlobalRef(android_api->godot_android_get_activity()); + jobject activity_object = env->NewGlobalRef(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity()); XrLoaderInitInfoAndroidKHR loader_init_info_android = { .type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, @@ -62,7 +64,7 @@ OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : .applicationVM = vm, .applicationContext = activity_object }; - xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android); + XrResult result = xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android); ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR"); } diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/openxr_android_extension.h index 88b0e310e7..eda7022064 100644 --- a/modules/openxr/extensions/openxr_android_extension.h +++ b/modules/openxr/extensions/openxr_android_extension.h @@ -31,6 +31,7 @@ #ifndef OPENXR_ANDROID_EXTENSION_H #define OPENXR_ANDROID_EXTENSION_H +#include "../util.h" #include "openxr_extension_wrapper.h" class OpenXRAndroidExtension : public OpenXRExtensionWrapper { @@ -38,10 +39,16 @@ public: static OpenXRAndroidExtension *get_singleton(); OpenXRAndroidExtension(OpenXRAPI *p_openxr_api); + + virtual void on_before_instance_created() override; + virtual ~OpenXRAndroidExtension() override; private: static OpenXRAndroidExtension *singleton; + + // Initialize the loader + EXT_PROTO_XRRESULT_FUNC1(xrInitializeLoaderKHR, (const XrLoaderInitInfoBaseHeaderKHR *), loaderInitInfo) }; #endif // OPENXR_ANDROID_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_composition_layer_provider.h b/modules/openxr/extensions/openxr_composition_layer_provider.h index 019dffa2a8..ba51389f7d 100644 --- a/modules/openxr/extensions/openxr_composition_layer_provider.h +++ b/modules/openxr/extensions/openxr_composition_layer_provider.h @@ -36,10 +36,9 @@ // Interface for OpenXR extensions that provide a composition layer. class OpenXRCompositionLayerProvider { public: - // TODO changed to normal method definition for now - // CI complains until we implement this, haven't ported it yet from plugin - // virtual XrCompositionLayerBaseHeader *get_composition_layer() = 0; - XrCompositionLayerBaseHeader *get_composition_layer() { return nullptr; }; + virtual XrCompositionLayerBaseHeader *get_composition_layer() = 0; + + virtual ~OpenXRCompositionLayerProvider() {} }; #endif // OPENXR_COMPOSITION_LAYER_PROVIDER_H diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index ecc6e0dd4e..623c264e6e 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -66,6 +66,7 @@ public: virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void on_before_instance_created() {} virtual void on_instance_created(const XrInstance p_instance) {} virtual void on_instance_destroyed() {} virtual void on_session_created(const XrSession p_instance) {} @@ -87,6 +88,11 @@ public: return false; } + // Return false if this extension is responsible for this path but the path is not enabled + virtual bool is_path_supported(const String &p_path) { + return true; + } + OpenXRExtensionWrapper(OpenXRAPI *p_openxr_api) { openxr_api = p_openxr_api; }; virtual ~OpenXRExtensionWrapper() = default; }; diff --git a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp new file mode 100644 index 0000000000..259b1236a3 --- /dev/null +++ b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp @@ -0,0 +1,234 @@ +/*************************************************************************/ +/* openxr_fb_passthrough_extension_wrapper.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_fb_passthrough_extension_wrapper.h" + +#include "core/os/os.h" +#include "scene/main/viewport.h" +#include "scene/main/window.h" + +using namespace godot; + +OpenXRFbPassthroughExtensionWrapper *OpenXRFbPassthroughExtensionWrapper::singleton = nullptr; + +OpenXRFbPassthroughExtensionWrapper *OpenXRFbPassthroughExtensionWrapper::get_singleton() { + return singleton; +} + +OpenXRFbPassthroughExtensionWrapper::OpenXRFbPassthroughExtensionWrapper(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + request_extensions[XR_FB_PASSTHROUGH_EXTENSION_NAME] = &fb_passthrough_ext; + request_extensions[XR_FB_TRIANGLE_MESH_EXTENSION_NAME] = &fb_triangle_mesh_ext; + singleton = this; +} + +OpenXRFbPassthroughExtensionWrapper::~OpenXRFbPassthroughExtensionWrapper() { + cleanup(); +} + +void OpenXRFbPassthroughExtensionWrapper::cleanup() { + fb_passthrough_ext = false; + fb_triangle_mesh_ext = false; +} + +Viewport *OpenXRFbPassthroughExtensionWrapper::get_main_viewport() { + MainLoop *main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) { + print_error("Unable to retrieve main loop"); + return nullptr; + } + + auto *scene_tree = Object::cast_to<SceneTree>(main_loop); + if (!scene_tree) { + print_error("Unable to retrieve scene tree"); + return nullptr; + } + + Viewport *viewport = scene_tree->get_root()->get_viewport(); + return viewport; +} + +void OpenXRFbPassthroughExtensionWrapper::on_instance_created(const XrInstance instance) { + if (fb_passthrough_ext) { + bool result = initialize_fb_passthrough_extension(instance); + if (!result) { + print_error("Failed to initialize fb_passthrough extension"); + fb_passthrough_ext = false; + } + } + + if (fb_triangle_mesh_ext) { + bool result = initialize_fb_triangle_mesh_extension(instance); + if (!result) { + print_error("Failed to initialize fb_triangle_mesh extension"); + fb_triangle_mesh_ext = false; + } + } + + if (fb_passthrough_ext) { + openxr_api->register_composition_layer_provider(this); + } +} + +bool OpenXRFbPassthroughExtensionWrapper::is_passthrough_enabled() { + return fb_passthrough_ext && passthrough_handle != XR_NULL_HANDLE && passthrough_layer != XR_NULL_HANDLE; +} + +bool OpenXRFbPassthroughExtensionWrapper::is_composition_passthrough_layer_ready() { + return fb_passthrough_ext && passthrough_handle != XR_NULL_HANDLE && composition_passthrough_layer.layerHandle != XR_NULL_HANDLE; +} + +bool OpenXRFbPassthroughExtensionWrapper::start_passthrough() { + if (passthrough_handle == XR_NULL_HANDLE) { + return false; + } + + if (is_passthrough_enabled()) { + return true; + } + + // Start the passthrough feature + XrResult result = xrPassthroughStartFB(passthrough_handle); + if (!is_valid_passthrough_result(result, "Failed to start passthrough")) { + stop_passthrough(); + return false; + } + + // Create the passthrough layer + result = xrCreatePassthroughLayerFB(openxr_api->get_session(), &passthrough_layer_config, &passthrough_layer); + if (!is_valid_passthrough_result(result, "Failed to create the passthrough layer")) { + stop_passthrough(); + return false; + } + + // Check if the the viewport has transparent background + Viewport *viewport = get_main_viewport(); + if (viewport && !viewport->has_transparent_background()) { + print_error("Main viewport doesn't have transparent background! Passthrough may not properly render."); + } + + composition_passthrough_layer.layerHandle = passthrough_layer; + + return true; +} + +void OpenXRFbPassthroughExtensionWrapper::on_session_created(const XrSession session) { + if (fb_passthrough_ext) { + // Create the passthrough feature and start it. + XrResult result = xrCreatePassthroughFB(openxr_api->get_session(), &passthrough_create_info, &passthrough_handle); + if (!openxr_api->xr_result(result, "Failed to create passthrough")) { + passthrough_handle = XR_NULL_HANDLE; + return; + } + } +} + +XrCompositionLayerBaseHeader *OpenXRFbPassthroughExtensionWrapper::get_composition_layer() { + if (is_composition_passthrough_layer_ready()) { + return (XrCompositionLayerBaseHeader *)&composition_passthrough_layer; + } else { + return nullptr; + } +} + +void OpenXRFbPassthroughExtensionWrapper::stop_passthrough() { + if (!fb_passthrough_ext) { + return; + } + + composition_passthrough_layer.layerHandle = XR_NULL_HANDLE; + + XrResult result; + if (passthrough_layer != XR_NULL_HANDLE) { + // Destroy the layer + result = xrDestroyPassthroughLayerFB(passthrough_layer); + openxr_api->xr_result(result, "Unable to destroy passthrough layer"); + passthrough_layer = XR_NULL_HANDLE; + } + + if (passthrough_handle != XR_NULL_HANDLE) { + result = xrPassthroughPauseFB(passthrough_handle); + openxr_api->xr_result(result, "Unable to stop passthrough feature"); + } +} + +void OpenXRFbPassthroughExtensionWrapper::on_session_destroyed() { + if (fb_passthrough_ext) { + stop_passthrough(); + + XrResult result; + if (passthrough_handle != XR_NULL_HANDLE) { + result = xrDestroyPassthroughFB(passthrough_handle); + openxr_api->xr_result(result, "Unable to destroy passthrough feature"); + passthrough_handle = XR_NULL_HANDLE; + } + } +} + +void OpenXRFbPassthroughExtensionWrapper::on_instance_destroyed() { + if (fb_passthrough_ext) { + openxr_api->unregister_composition_layer_provider(this); + } + cleanup(); +} + +bool OpenXRFbPassthroughExtensionWrapper::initialize_fb_passthrough_extension(const XrInstance p_instance) { + ERR_FAIL_NULL_V(openxr_api, false); + + EXT_INIT_XR_FUNC_V(xrCreatePassthroughFB); + EXT_INIT_XR_FUNC_V(xrDestroyPassthroughFB); + EXT_INIT_XR_FUNC_V(xrPassthroughStartFB); + EXT_INIT_XR_FUNC_V(xrPassthroughPauseFB); + EXT_INIT_XR_FUNC_V(xrCreatePassthroughLayerFB); + EXT_INIT_XR_FUNC_V(xrDestroyPassthroughLayerFB); + EXT_INIT_XR_FUNC_V(xrPassthroughLayerPauseFB); + EXT_INIT_XR_FUNC_V(xrPassthroughLayerResumeFB); + EXT_INIT_XR_FUNC_V(xrPassthroughLayerSetStyleFB); + EXT_INIT_XR_FUNC_V(xrCreateGeometryInstanceFB); + EXT_INIT_XR_FUNC_V(xrDestroyGeometryInstanceFB); + EXT_INIT_XR_FUNC_V(xrGeometryInstanceSetTransformFB); + + return true; +} + +bool OpenXRFbPassthroughExtensionWrapper::initialize_fb_triangle_mesh_extension(const XrInstance p_instance) { + ERR_FAIL_NULL_V(openxr_api, false); + + EXT_INIT_XR_FUNC_V(xrCreateTriangleMeshFB); + EXT_INIT_XR_FUNC_V(xrDestroyTriangleMeshFB); + EXT_INIT_XR_FUNC_V(xrTriangleMeshGetVertexBufferFB); + EXT_INIT_XR_FUNC_V(xrTriangleMeshGetIndexBufferFB); + EXT_INIT_XR_FUNC_V(xrTriangleMeshBeginUpdateFB); + EXT_INIT_XR_FUNC_V(xrTriangleMeshEndUpdateFB); + EXT_INIT_XR_FUNC_V(xrTriangleMeshBeginVertexBufferUpdateFB); + EXT_INIT_XR_FUNC_V(xrTriangleMeshEndVertexBufferUpdateFB); + + return true; +} diff --git a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h new file mode 100644 index 0000000000..1959f3fdc4 --- /dev/null +++ b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h @@ -0,0 +1,254 @@ +/*************************************************************************/ +/* openxr_fb_passthrough_extension_wrapper.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_FB_PASSTHROUGH_EXTENSION_WRAPPER_H +#define OPENXR_FB_PASSTHROUGH_EXTENSION_WRAPPER_H + +#include "../openxr_api.h" +#include "../util.h" + +#include "openxr_composition_layer_provider.h" +#include "openxr_extension_wrapper.h" + +#include <map> + +class Viewport; + +// Wrapper for the set of Facebook XR passthrough extensions. +class OpenXRFbPassthroughExtensionWrapper : public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider { + friend class OpenXRAPI; + +public: + void on_instance_created(const XrInstance instance) override; + + void on_session_created(const XrSession session) override; + + void on_session_destroyed() override; + + void on_instance_destroyed() override; + + XrCompositionLayerBaseHeader *get_composition_layer() override; + + bool is_passthrough_supported() { + return fb_passthrough_ext; + } + + bool is_passthrough_enabled(); + + bool start_passthrough(); + + void stop_passthrough(); + + static OpenXRFbPassthroughExtensionWrapper *get_singleton(); + +protected: + OpenXRFbPassthroughExtensionWrapper(OpenXRAPI *p_openxr_api); + ~OpenXRFbPassthroughExtensionWrapper(); + +private: + // Create a passthrough feature + EXT_PROTO_XRRESULT_FUNC3(xrCreatePassthroughFB, + (XrSession), session, + (const XrPassthroughCreateInfoFB *), create_info, + (XrPassthroughFB *), feature_out) + + // Destroy a previously created passthrough feature + EXT_PROTO_XRRESULT_FUNC1(xrDestroyPassthroughFB, (XrPassthroughFB), feature) + + //*** Passthrough feature state management functions ********* + // Start the passthrough feature + EXT_PROTO_XRRESULT_FUNC1(xrPassthroughStartFB, (XrPassthroughFB), passthrough) + // Pause the passthrough feature + EXT_PROTO_XRRESULT_FUNC1(xrPassthroughPauseFB, (XrPassthroughFB), passthrough) + + EXT_PROTO_XRRESULT_FUNC3(xrCreatePassthroughLayerFB, (XrSession), session, + (const XrPassthroughLayerCreateInfoFB *), config, + (XrPassthroughLayerFB *), layer_out) + + EXT_PROTO_XRRESULT_FUNC1(xrDestroyPassthroughLayerFB, (XrPassthroughLayerFB), layer) + + EXT_PROTO_XRRESULT_FUNC1(xrPassthroughLayerPauseFB, (XrPassthroughLayerFB), layer) + EXT_PROTO_XRRESULT_FUNC1(xrPassthroughLayerResumeFB, (XrPassthroughLayerFB), layer) + + // Set the style of an existing passthrough layer. If the enabled feature set + // doesn’t change, this is a lightweight operation that can be called in every + // frame to animate the style. Changes that may incur a bigger cost: + // - Enabling/disabling the color mapping, or changing the type of mapping + // (monochromatic to RGBA or back). + // - Changing `textureOpacityFactor` from 0 to non-zero or vice versa + // - Changing `edgeColor[3]` from 0 to non-zero or vice versa + // NOTE: For XR_FB_passthrough, all color values are treated as linear. + EXT_PROTO_XRRESULT_FUNC2(xrPassthroughLayerSetStyleFB, + (XrPassthroughLayerFB), layer, + (const XrPassthroughStyleFB *), style) + + // Create a geometry instance to be used as a projection surface for passthrough. + // A geometry instance assigns a triangle mesh as part of the specified layer's + // projection surface. + // The operation is only valid if the passthrough layer's purpose has been set to + // `XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB`. Otherwise, the call this function will + // result in an error. In the specified layer, Passthrough will be visible where the view + // is covered by the user-specified geometries. + // + // A triangle mesh object can be instantiated multiple times - in the same or different layers' + // projection surface. Each instantiation has its own transformation, which + // can be updated using `xrGeometryInstanceSetTransformFB`. + EXT_PROTO_XRRESULT_FUNC3(xrCreateGeometryInstanceFB, + (XrSession), session, + (const XrGeometryInstanceCreateInfoFB *), create_info, + (XrGeometryInstanceFB *), out_geometry_instance) + + // Destroys a previously created geometry instance from passthrough rendering. + // This removes the geometry instance from passthrough rendering. + // The operation has no effect on other instances or the underlying mesh. + EXT_PROTO_XRRESULT_FUNC1(xrDestroyGeometryInstanceFB, (XrGeometryInstanceFB), instance) + + // Update the transformation of a passthrough geometry instance. + EXT_PROTO_XRRESULT_FUNC2(xrGeometryInstanceSetTransformFB, + (XrGeometryInstanceFB), instance, + (const XrGeometryInstanceTransformFB *), transformation) + + // Create a triangle mesh geometry object. + // Depending on the behavior flags, the mesh could be created immutable (data is assigned + // at creation and cannot be changed) or mutable (the mesh is created empty and can be updated + // by calling begin/end update functions). + EXT_PROTO_XRRESULT_FUNC3(xrCreateTriangleMeshFB, + (XrSession), session, + (const XrTriangleMeshCreateInfoFB *), create_info, + (XrTriangleMeshFB *), out_triangle_mesh) + + // Destroy an `XrTriangleMeshFB` object along with its data. The mesh buffers must not be + // accessed anymore after their parent mesh object has been destroyed. + EXT_PROTO_XRRESULT_FUNC1(xrDestroyTriangleMeshFB, (XrTriangleMeshFB), mesh) + + // Retrieve a pointer to the vertex buffer. The vertex buffer is structured as an array of 3 floats + // per vertex representing x, y, and z: `[x0, y0, z0, x1, y1, z1, ...]`. The size of the buffer is + // `maxVertexCount * 3` floats. The application must call `xrTriangleMeshBeginUpdateFB` or + // `xrTriangleMeshBeginVertexBufferUpdateFB` before making modifications to the vertex + // buffer. The buffer location is guaranteed to remain constant over the lifecycle of the mesh + // object. + EXT_PROTO_XRRESULT_FUNC2(xrTriangleMeshGetVertexBufferFB, + (XrTriangleMeshFB), mesh, + (XrVector3f **), out_vertex_buffer) + + // Retrieve the index buffer that defines the topology of the triangle mesh. Each triplet of + // consecutive elements point to three vertices in the vertex buffer and thus form a triangle. The + // size of each element is `indexElementSize` bytes, and thus the size of the buffer is + // `maxTriangleCount * 3 * indexElementSize` bytes. The application must call + // `xrTriangleMeshBeginUpdateFB` before making modifications to the index buffer. The buffer + // location is guaranteed to remain constant over the lifecycle of the mesh object. + EXT_PROTO_XRRESULT_FUNC2(xrTriangleMeshGetIndexBufferFB, + (XrTriangleMeshFB), mesh, + (uint32_t **), out_index_buffer) + + // Begin updating the mesh buffer data. The application must call this function before it makes any + // modifications to the buffers retrieved by `xrTriangleMeshGetVertexBufferFB` and + // `xrTriangleMeshGetIndexBufferFB`. If only the vertex buffer needs to be updated, + // `xrTriangleMeshBeginVertexBufferUpdateFB` can be used instead. To commit the + // modifications, the application must call `xrTriangleMeshEndUpdateFB`. + EXT_PROTO_XRRESULT_FUNC1(xrTriangleMeshBeginUpdateFB, (XrTriangleMeshFB), mesh) + + // Signal the API that the application has finished updating the mesh buffers after a call to + // `xrTriangleMeshBeginUpdateFB`. `vertexCount` and `triangleCount` specify the actual + // number of primitives that make up the mesh after the update. They must be larger than zero but + // smaller or equal to the maximum counts defined at create time. Buffer data beyond these counts + // is ignored. + EXT_PROTO_XRRESULT_FUNC3(xrTriangleMeshEndUpdateFB, + (XrTriangleMeshFB), mesh, + (uint32_t), vertexCount, + (uint32_t), triangle_count) + + // Update the vertex positions of a triangle mesh. Can only be called once the mesh topology has + // been set using `xrTriangleMeshBeginUpdateFB`/`xrTriangleMeshEndUpdateFB`. The + // vertex count is defined by the last invocation to `xrTriangleMeshEndUpdateFB`. Once the + // modification is done, `xrTriangleMeshEndVertexBufferUpdateFB` must be called. + EXT_PROTO_XRRESULT_FUNC2(xrTriangleMeshBeginVertexBufferUpdateFB, + (XrTriangleMeshFB), mesh, + (uint32_t *), out_vertex_count) + + // Signal the API that the contents of the vertex buffer data has been updated + // after a call to `xrTriangleMeshBeginVertexBufferUpdateFB`. + EXT_PROTO_XRRESULT_FUNC1(xrTriangleMeshEndVertexBufferUpdateFB, (XrTriangleMeshFB), mesh) + + bool initialize_fb_passthrough_extension(const XrInstance instance); + + bool initialize_fb_triangle_mesh_extension(const XrInstance instance); + + void cleanup(); + + // TODO: Temporary workaround (https://github.com/GodotVR/godot_openxr/issues/138) + // Address a bug in the passthrough api where XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB is + // returned even when the operation is valid on Meta Quest devices. + // The issue should be addressed on that platform in OS release v37. + inline bool is_valid_passthrough_result(XrResult result, const char *format) { + return openxr_api->xr_result(result, format) || result == XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB; + } + + Viewport *get_main_viewport(); + + bool is_composition_passthrough_layer_ready(); + + static OpenXRFbPassthroughExtensionWrapper *singleton; + + bool fb_passthrough_ext = false; // required for any passthrough functionality + bool fb_triangle_mesh_ext = false; // only use for projected passthrough + + XrPassthroughCreateInfoFB passthrough_create_info = { + XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, + nullptr, + 0, + }; + XrPassthroughFB passthrough_handle = XR_NULL_HANDLE; + + XrPassthroughLayerCreateInfoFB passthrough_layer_config = { + XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, + nullptr, + passthrough_handle, + XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, + XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, + }; + XrPassthroughStyleFB passthrough_layer_style = { + XR_TYPE_PASSTHROUGH_STYLE_FB, + nullptr, + 1, + { 0, 0, 0, 0 }, + }; + XrPassthroughLayerFB passthrough_layer = XR_NULL_HANDLE; + + XrCompositionLayerPassthroughFB composition_passthrough_layer = { + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, + nullptr, + XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, + XR_NULL_HANDLE, + XR_NULL_HANDLE, + }; +}; + +#endif // OPENXR_FB_PASSTHROUGH_EXTENSION_WRAPPER_H diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp new file mode 100644 index 0000000000..4b30965ce5 --- /dev/null +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -0,0 +1,268 @@ +/*************************************************************************/ +/* openxr_hand_tracking_extension.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_hand_tracking_extension.h" +#include "../openxr_api.h" +#include "core/string/print_string.h" +#include "servers/xr_server.h" + +#include <openxr/openxr.h> + +OpenXRHandTrackingExtension *OpenXRHandTrackingExtension::singleton = nullptr; + +OpenXRHandTrackingExtension *OpenXRHandTrackingExtension::get_singleton() { + return singleton; +} + +OpenXRHandTrackingExtension::OpenXRHandTrackingExtension(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + singleton = this; + + // Extensions we use for our hand tracking. + request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext; + request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext; + request_extensions[XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME] = &hand_tracking_aim_state_ext; + + // Make sure this is cleared until we actually request it + handTrackingSystemProperties.supportsHandTracking = false; +} + +OpenXRHandTrackingExtension::~OpenXRHandTrackingExtension() { + singleton = nullptr; +} + +void OpenXRHandTrackingExtension::on_instance_created(const XrInstance p_instance) { + if (hand_tracking_ext) { + EXT_INIT_XR_FUNC(xrCreateHandTrackerEXT); + EXT_INIT_XR_FUNC(xrDestroyHandTrackerEXT); + EXT_INIT_XR_FUNC(xrLocateHandJointsEXT); + + hand_tracking_ext = xrCreateHandTrackerEXT_ptr && xrDestroyHandTrackerEXT_ptr && xrLocateHandJointsEXT_ptr; + } +} + +void OpenXRHandTrackingExtension::on_session_destroyed() { + cleanup_hand_tracking(); +} + +void OpenXRHandTrackingExtension::on_instance_destroyed() { + xrCreateHandTrackerEXT_ptr = nullptr; + xrDestroyHandTrackerEXT_ptr = nullptr; + xrLocateHandJointsEXT_ptr = nullptr; +} + +void *OpenXRHandTrackingExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) { + if (!hand_tracking_ext) { + // not supported... + return p_next_pointer; + } + + handTrackingSystemProperties = { + XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, // type + p_next_pointer, // next + false, // supportsHandTracking + }; + + return &handTrackingSystemProperties; +} + +void OpenXRHandTrackingExtension::on_state_ready() { + if (!handTrackingSystemProperties.supportsHandTracking) { + // not supported... + return; + } + + // Setup our hands and reset data + for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { + // we'll do this later + hand_trackers[i].is_initialised = false; + hand_trackers[i].hand_tracker = XR_NULL_HANDLE; + + hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }; + hand_trackers[i].aimState.pinchStrengthIndex = 0.0; + hand_trackers[i].aimState.pinchStrengthMiddle = 0.0; + hand_trackers[i].aimState.pinchStrengthRing = 0.0; + hand_trackers[i].aimState.pinchStrengthLittle = 0.0; + + hand_trackers[i].locations.isActive = false; + + for (int j = 0; j < XR_HAND_JOINT_COUNT_EXT; j++) { + hand_trackers[i].joint_locations[j] = { 0, { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }, 0.0 }; + hand_trackers[i].joint_velocities[j] = { 0, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }; + } + } +} + +void OpenXRHandTrackingExtension::on_process() { + if (!handTrackingSystemProperties.supportsHandTracking) { + // not supported... + return; + } + + // process our hands + const XrTime time = openxr_api->get_next_frame_time(); // This data will be used for the next frame we render + + XrResult result; + + for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { + if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) { + XrHandTrackerCreateInfoEXT createInfo = { + XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type + nullptr, // next + i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand + XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet + }; + + result = xrCreateHandTrackerEXT(openxr_api->get_session(), &createInfo, &hand_trackers[i].hand_tracker); + if (XR_FAILED(result)) { + // not successful? then we do nothing. + print_line("OpenXR: Failed to obtain hand tracking information [", openxr_api->get_error_string(result), "]"); + hand_trackers[i].is_initialised = false; + } else { + void *next_pointer = nullptr; + if (hand_tracking_aim_state_ext) { + hand_trackers[i].aimState.type = XR_TYPE_HAND_TRACKING_AIM_STATE_FB; + hand_trackers[i].aimState.next = next_pointer; + hand_trackers[i].aimState.status = 0; + hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }; + hand_trackers[i].aimState.pinchStrengthIndex = 0.0; + hand_trackers[i].aimState.pinchStrengthMiddle = 0.0; + hand_trackers[i].aimState.pinchStrengthRing = 0.0; + hand_trackers[i].aimState.pinchStrengthLittle = 0.0; + + next_pointer = &hand_trackers[i].aimState; + } + + hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT; + hand_trackers[i].velocities.next = next_pointer; + hand_trackers[i].velocities.jointCount = XR_HAND_JOINT_COUNT_EXT; + hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities; + next_pointer = &hand_trackers[i].velocities; + + hand_trackers[i].locations.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT; + hand_trackers[i].locations.next = next_pointer; + hand_trackers[i].locations.isActive = false; + hand_trackers[i].locations.jointCount = XR_HAND_JOINT_COUNT_EXT; + hand_trackers[i].locations.jointLocations = hand_trackers[i].joint_locations; + + hand_trackers[i].is_initialised = true; + } + } + + if (hand_trackers[i].is_initialised) { + void *next_pointer = nullptr; + + XrHandJointsMotionRangeInfoEXT motionRangeInfo; + + if (hand_motion_range_ext) { + motionRangeInfo.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT; + motionRangeInfo.next = next_pointer; + motionRangeInfo.handJointsMotionRange = hand_trackers[i].motion_range; + + next_pointer = &motionRangeInfo; + } + + XrHandJointsLocateInfoEXT locateInfo = { + XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, // type + next_pointer, // next + openxr_api->get_play_space(), // baseSpace + time, // time + }; + + result = xrLocateHandJointsEXT(hand_trackers[i].hand_tracker, &locateInfo, &hand_trackers[i].locations); + if (XR_FAILED(result)) { + // not successful? then we do nothing. + print_line("OpenXR: Failed to get tracking for hand", i, "[", openxr_api->get_error_string(result), "]"); + continue; + } + + // For some reason an inactive controller isn't coming back as inactive but has coordinates either as NAN or very large + const XrPosef &palm = hand_trackers[i].joint_locations[XR_HAND_JOINT_PALM_EXT].pose; + if ( + !hand_trackers[i].locations.isActive || isnan(palm.position.x) || palm.position.x < -1000000.00 || palm.position.x > 1000000.00) { + hand_trackers[i].locations.isActive = false; // workaround, make sure its inactive + } + + /* TODO change this to managing the controller from openxr_interface + if (hand_tracking_aim_state_ext && hand_trackers[i].locations.isActive && check_bit(XR_HAND_TRACKING_AIM_VALID_BIT_FB, hand_trackers[i].aimState.status)) { + // Controllers are updated based on the aim state's pose and pinches' strength + if (hand_trackers[i].aim_state_godot_controller == -1) { + hand_trackers[i].aim_state_godot_controller = + arvr_api->godot_arvr_add_controller( + const_cast<char *>(hand_controller_names[i]), + i + HAND_CONTROLLER_ID_OFFSET, + true, + true); + } + } + */ + } + } +} + +void OpenXRHandTrackingExtension::on_state_stopping() { + // cleanup + cleanup_hand_tracking(); +} + +void OpenXRHandTrackingExtension::cleanup_hand_tracking() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); + + for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { + if (hand_trackers[i].hand_tracker != XR_NULL_HANDLE) { + xrDestroyHandTrackerEXT(hand_trackers[i].hand_tracker); + + hand_trackers[i].is_initialised = false; + hand_trackers[i].hand_tracker = XR_NULL_HANDLE; + } + } +} + +bool OpenXRHandTrackingExtension::get_active() { + return handTrackingSystemProperties.supportsHandTracking; +} + +const OpenXRHandTrackingExtension::HandTracker *OpenXRHandTrackingExtension::get_hand_tracker(uint32_t p_hand) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, nullptr); + + return &hand_trackers[p_hand]; +} + +XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(uint32_t p_hand) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT); + + return hand_trackers[p_hand].motion_range; +} + +void OpenXRHandTrackingExtension::set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range) { + ERR_FAIL_UNSIGNED_INDEX(p_hand, MAX_OPENXR_TRACKED_HANDS); + hand_trackers[p_hand].motion_range = p_motion_range; +} diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h new file mode 100644 index 0000000000..f8c26339b0 --- /dev/null +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* openxr_hand_tracking_extension.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_HAND_TRACKING_EXTENSION_H +#define OPENXR_HAND_TRACKING_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +#include "../util.h" + +#define MAX_OPENXR_TRACKED_HANDS 2 + +class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper { +public: + struct HandTracker { + bool is_initialised = false; + XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; + + XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE; + XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT]; + XrHandJointVelocityEXT joint_velocities[XR_HAND_JOINT_COUNT_EXT]; + + XrHandTrackingAimStateFB aimState; + XrHandJointVelocitiesEXT velocities; + XrHandJointLocationsEXT locations; + }; + + static OpenXRHandTrackingExtension *get_singleton(); + + OpenXRHandTrackingExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRHandTrackingExtension() override; + + virtual void on_instance_created(const XrInstance p_instance) override; + virtual void on_instance_destroyed() override; + virtual void on_session_destroyed() override; + + virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override; + virtual void on_state_ready() override; + virtual void on_process() override; + virtual void on_state_stopping() override; + + bool get_active(); + const HandTracker *get_hand_tracker(uint32_t p_hand) const; + + XrHandJointsMotionRangeEXT get_motion_range(uint32_t p_hand) const; + void set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range); + +private: + static OpenXRHandTrackingExtension *singleton; + + // state + XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties; + HandTracker hand_trackers[MAX_OPENXR_TRACKED_HANDS]; // Fixed for left and right hand + + // related extensions + bool hand_tracking_ext = false; + bool hand_motion_range_ext = false; + bool hand_tracking_aim_state_ext = false; + + // functions + void cleanup_hand_tracking(); + + // OpenXR API call wrappers + EXT_PROTO_XRRESULT_FUNC3(xrCreateHandTrackerEXT, (XrSession), p_session, (const XrHandTrackerCreateInfoEXT *), p_createInfo, (XrHandTrackerEXT *), p_handTracker) + EXT_PROTO_XRRESULT_FUNC1(xrDestroyHandTrackerEXT, (XrHandTrackerEXT), p_handTracker) + EXT_PROTO_XRRESULT_FUNC3(xrLocateHandJointsEXT, (XrHandTrackerEXT), p_handTracker, (const XrHandJointsLocateInfoEXT *), p_locateInfo, (XrHandJointLocationsEXT *), p_locations) +}; + +#endif // OPENXR_HAND_TRACKING_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp index 302acf4e30..88cc7c061c 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp @@ -65,3 +65,12 @@ bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &eve } break; } } + +bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) { + if (p_path == "/interaction_profiles/htc/vive_tracker_htcx") { + return available; + } + + // Not a path under this extensions control, so we return true; + return true; +} diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h index 7f37351f27..ab8e8535f1 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h @@ -41,7 +41,9 @@ public: virtual ~OpenXRHTCViveTrackerExtension() override; bool is_available(); + virtual bool on_event_polled(const XrEventDataBuffer &event) override; + virtual bool is_path_supported(const String &p_path) override; private: static OpenXRHTCViveTrackerExtension *singleton; diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.cpp b/modules/openxr/extensions/openxr_palm_pose_extension.cpp new file mode 100644 index 0000000000..fd3b8f50fe --- /dev/null +++ b/modules/openxr/extensions/openxr_palm_pose_extension.cpp @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* openxr_palm_pose_extension.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_palm_pose_extension.h" +#include "core/string/print_string.h" + +OpenXRPalmPoseExtension *OpenXRPalmPoseExtension::singleton = nullptr; + +OpenXRPalmPoseExtension *OpenXRPalmPoseExtension::get_singleton() { + return singleton; +} + +OpenXRPalmPoseExtension::OpenXRPalmPoseExtension(OpenXRAPI *p_openxr_api) : + OpenXRExtensionWrapper(p_openxr_api) { + singleton = this; + + request_extensions[XR_EXT_PALM_POSE_EXTENSION_NAME] = &available; +} + +OpenXRPalmPoseExtension::~OpenXRPalmPoseExtension() { + singleton = nullptr; +} + +bool OpenXRPalmPoseExtension::is_available() { + return available; +} + +bool OpenXRPalmPoseExtension::is_path_supported(const String &p_path) { + if (p_path == "/user/hand/left/input/palm_ext/pose") { + return available; + } + + if (p_path == "/user/hand/right/input/palm_ext/pose") { + return available; + } + + // Not a path under this extensions control, so we return true; + return true; +} diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.h b/modules/openxr/extensions/openxr_palm_pose_extension.h new file mode 100644 index 0000000000..a7ef83c5d5 --- /dev/null +++ b/modules/openxr/extensions/openxr_palm_pose_extension.h @@ -0,0 +1,53 @@ +/*************************************************************************/ +/* openxr_palm_pose_extension.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_PALM_POSE_EXTENSION_H +#define OPENXR_PALM_POSE_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRPalmPoseExtension : public OpenXRExtensionWrapper { +public: + static OpenXRPalmPoseExtension *get_singleton(); + + OpenXRPalmPoseExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXRPalmPoseExtension() override; + + bool is_available(); + + virtual bool is_path_supported(const String &p_path) override; + +private: + static OpenXRPalmPoseExtension *singleton; + + bool available = false; +}; + +#endif // OPENXR_PALM_POSE_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp index 2608c4ac17..f9e771c934 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -31,30 +31,12 @@ #include "core/string/print_string.h" #include "../extensions/openxr_vulkan_extension.h" -#include "../openxr_api.h" #include "../openxr_util.h" #include "servers/rendering/renderer_rd/effects/copy_effects.h" #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" #include "servers/rendering/rendering_server_globals.h" #include "servers/rendering_server.h" -// need to include Vulkan so we know of type definitions -#define XR_USE_GRAPHICS_API_VULKAN - -#ifdef WINDOWS_ENABLED -// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform -// however due to the way the openxr headers are put together, we have no choice. -#include <windows.h> -#endif - -// include platform dependent structs -#include <openxr/openxr_platform.h> - -PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR_ptr = nullptr; -PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR_ptr = nullptr; -PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR_ptr = nullptr; -PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR_ptr = nullptr; - OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) : OpenXRGraphicsExtensionWrapper(p_openxr_api) { VulkanContext::set_vulkan_hooks(this); @@ -69,36 +51,15 @@ OpenXRVulkanExtension::~OpenXRVulkanExtension() { } void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) { - XrResult result; - ERR_FAIL_NULL(openxr_api); // Obtain pointers to functions we're accessing here, they are (not yet) part of core. - result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR_ptr); - if (XR_FAILED(result)) { - print_line("OpenXR: Failed to xrGetVulkanGraphicsRequirements2KHR entry point [", openxr_api->get_error_string(result), "]"); - } - result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR_ptr); - if (XR_FAILED(result)) { - print_line("OpenXR: Failed to xrCreateVulkanInstanceKHR entry point [", openxr_api->get_error_string(result), "]"); - } - - result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR_ptr); - if (XR_FAILED(result)) { - print_line("OpenXR: Failed to xrGetVulkanGraphicsDevice2KHR entry point [", openxr_api->get_error_string(result), "]"); - } - - result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR_ptr); - if (XR_FAILED(result)) { - print_line("OpenXR: Failed to xrCreateVulkanDeviceKHR entry point [", openxr_api->get_error_string(result), "]"); - } -} - -XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements) { - ERR_FAIL_NULL_V(xrGetVulkanGraphicsRequirements2KHR_ptr, XR_ERROR_HANDLE_INVALID); - - return (*xrGetVulkanGraphicsRequirements2KHR_ptr)(p_instance, p_system_id, p_graphics_requirements); + EXT_INIT_XR_FUNC(xrGetVulkanGraphicsRequirements2KHR); + EXT_INIT_XR_FUNC(xrCreateVulkanInstanceKHR); + EXT_INIT_XR_FUNC(xrGetVulkanGraphicsDevice2KHR); + EXT_INIT_XR_FUNC(xrCreateVulkanDeviceKHR); + EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages); } bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) { @@ -141,12 +102,6 @@ bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_versi return true; } -XrResult OpenXRVulkanExtension::xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result) { - ERR_FAIL_NULL_V(xrCreateVulkanInstanceKHR_ptr, XR_ERROR_HANDLE_INVALID); - - return (*xrCreateVulkanInstanceKHR_ptr)(p_instance, p_create_info, r_vulkan_instance, r_vulkan_result); -} - bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { // get the vulkan version we are creating uint32_t vulkan_version = p_vulkan_create_info->pApplicationInfo->apiVersion; @@ -195,12 +150,6 @@ bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p return true; } -XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device) { - ERR_FAIL_NULL_V(xrGetVulkanGraphicsDevice2KHR_ptr, XR_ERROR_HANDLE_INVALID); - - return (*xrGetVulkanGraphicsDevice2KHR_ptr)(p_instance, p_get_info, r_vulkan_physical_device); -} - bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) { ERR_FAIL_NULL_V(openxr_api, false); @@ -222,12 +171,6 @@ bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) { return true; } -XrResult OpenXRVulkanExtension::xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result) { - ERR_FAIL_NULL_V(xrCreateVulkanDeviceKHR_ptr, XR_ERROR_HANDLE_INVALID); - - return (*xrCreateVulkanDeviceKHR_ptr)(p_instance, p_create_info, r_device, r_result); -} - bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { ERR_FAIL_NULL_V(openxr_api, false); diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h index 5dddc4b9c9..d6e9917900 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.h +++ b/modules/openxr/extensions/openxr_vulkan_extension.h @@ -36,16 +36,25 @@ #include "drivers/vulkan/vulkan_context.h" -// Forward declare these so we don't need OpenXR headers where-ever this is included -// Including OpenXR at this point gives loads and loads of compile issues especially -// on Windows because windows.h is EVIL and really shouldn't be included outside of platform -// but we really don't have a choice in the matter +#include "../openxr_api.h" +#include "../util.h" -struct XrGraphicsRequirementsVulkanKHR; -struct XrVulkanInstanceCreateInfoKHR; -struct XrVulkanGraphicsDeviceGetInfoKHR; -struct XrVulkanDeviceCreateInfoKHR; -struct XrGraphicsBindingVulkanKHR; +// need to include Vulkan so we know of type definitions +#define XR_USE_GRAPHICS_API_VULKAN + +#ifdef WINDOWS_ENABLED +// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform +// however due to the way the openxr headers are put together, we have no choice. +#include <windows.h> +#endif + +#ifdef ANDROID_ENABLED +// The jobject type from jni.h is used by openxr_platform.h on Android. +#include <jni.h> +#endif + +// include platform dependent structs +#include <openxr/openxr_platform.h> class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks { public: @@ -84,10 +93,11 @@ private: uint32_t vulkan_queue_family_index = 0; uint32_t vulkan_queue_index = 0; - XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements); - XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result); - XrResult xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device); - XrResult xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result); + EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsRequirements2KHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsVulkanKHR *), p_graphics_requirements) + EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanInstanceKHR, (XrInstance), p_instance, (const XrVulkanInstanceCreateInfoKHR *), p_create_info, (VkInstance *), r_vulkan_instance, (VkResult *), r_vulkan_result) + EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsDevice2KHR, (XrInstance), p_instance, (const XrVulkanGraphicsDeviceGetInfoKHR *), p_get_info, (VkPhysicalDevice *), r_vulkan_physical_device) + EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanDeviceKHR, (XrInstance), p_instance, (const XrVulkanDeviceCreateInfoKHR *), p_create_info, (VkDevice *), r_device, (VkResult *), r_result) + EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images) }; #endif // OPENXR_VULKAN_EXTENSION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 94095eb61c..16879ac4e5 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -41,6 +41,7 @@ #endif #ifdef ANDROID_ENABLED +#define OPENXR_LOADER_NAME "libopenxr_loader.so" #include "extensions/openxr_android_extension.h" #endif @@ -48,7 +49,10 @@ #include "extensions/openxr_vulkan_extension.h" #endif +#include "extensions/openxr_fb_passthrough_extension_wrapper.h" +#include "extensions/openxr_hand_tracking_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" +#include "extensions/openxr_palm_pose_extension.h" #include "modules/openxr/openxr_interface.h" @@ -184,6 +188,20 @@ bool OpenXRAPI::is_extension_supported(const String &p_extension) const { return false; } +bool OpenXRAPI::is_path_supported(const String &p_path) { + // This checks with extensions whether a path is *unsupported* and returns false if this is so. + // This allows us to filter out paths that are only available if related extensions are supported. + // WARNING: This method will return true for unknown/mistyped paths as we have no way to validate those. + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + if (!wrapper->is_path_supported(p_path)) { + return false; + } + } + + return true; +} + void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) { CharString char_string = p_string.utf8(); int len = char_string.length(); @@ -284,6 +302,9 @@ bool OpenXRAPI::create_instance() { 0, // runtimeVersion, from here will be set by our get call "" // runtimeName }; + + OPENXR_API_INIT_XR_FUNC_V(xrGetInstanceProperties); + result = xrGetInstanceProperties(instance, &instanceProps); if (XR_FAILED(result)) { // not fatal probably @@ -992,9 +1013,94 @@ bool OpenXRAPI::is_running() { return running; } +bool OpenXRAPI::openxr_loader_init() { +#ifdef ANDROID_ENABLED + ERR_FAIL_COND_V_MSG(openxr_loader_library_handle != nullptr, false, "OpenXR Loader library is already loaded."); + + { + Error error_code = OS::get_singleton()->open_dynamic_library(OPENXR_LOADER_NAME, openxr_loader_library_handle); + ERR_FAIL_COND_V_MSG(error_code != OK, false, "OpenXR loader not found."); + } + + { + Error error_code = OS::get_singleton()->get_dynamic_library_symbol_handle(openxr_loader_library_handle, "xrGetInstanceProcAddr", (void *&)xrGetInstanceProcAddr); + ERR_FAIL_COND_V_MSG(error_code != OK, false, "Symbol xrGetInstanceProcAddr not found in OpenXR Loader library."); + } +#endif + + // Resolve the symbols that don't require an instance + OPENXR_API_INIT_XR_FUNC_V(xrCreateInstance); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateApiLayerProperties); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateInstanceExtensionProperties); + + return true; +} + +bool OpenXRAPI::resolve_instance_openxr_symbols() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + OPENXR_API_INIT_XR_FUNC_V(xrAcquireSwapchainImage); + OPENXR_API_INIT_XR_FUNC_V(xrApplyHapticFeedback); + OPENXR_API_INIT_XR_FUNC_V(xrAttachSessionActionSets); + OPENXR_API_INIT_XR_FUNC_V(xrBeginFrame); + OPENXR_API_INIT_XR_FUNC_V(xrBeginSession); + OPENXR_API_INIT_XR_FUNC_V(xrCreateAction); + OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSet); + OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSpace); + OPENXR_API_INIT_XR_FUNC_V(xrCreateReferenceSpace); + OPENXR_API_INIT_XR_FUNC_V(xrCreateSession); + OPENXR_API_INIT_XR_FUNC_V(xrCreateSwapchain); + OPENXR_API_INIT_XR_FUNC_V(xrDestroyAction); + OPENXR_API_INIT_XR_FUNC_V(xrDestroyActionSet); + OPENXR_API_INIT_XR_FUNC_V(xrDestroyInstance); + OPENXR_API_INIT_XR_FUNC_V(xrDestroySession); + OPENXR_API_INIT_XR_FUNC_V(xrDestroySpace); + OPENXR_API_INIT_XR_FUNC_V(xrDestroySwapchain); + OPENXR_API_INIT_XR_FUNC_V(xrEndFrame); + OPENXR_API_INIT_XR_FUNC_V(xrEndSession); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateReferenceSpaces); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateSwapchainFormats); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurations); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurationViews); + OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateBoolean); + OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat); + OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f); + OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile); + OPENXR_API_INIT_XR_FUNC_V(xrGetSystem); + OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties); + OPENXR_API_INIT_XR_FUNC_V(xrLocateViews); + OPENXR_API_INIT_XR_FUNC_V(xrLocateSpace); + OPENXR_API_INIT_XR_FUNC_V(xrPathToString); + OPENXR_API_INIT_XR_FUNC_V(xrPollEvent); + OPENXR_API_INIT_XR_FUNC_V(xrReleaseSwapchainImage); + OPENXR_API_INIT_XR_FUNC_V(xrResultToString); + OPENXR_API_INIT_XR_FUNC_V(xrStringToPath); + OPENXR_API_INIT_XR_FUNC_V(xrSuggestInteractionProfileBindings); + OPENXR_API_INIT_XR_FUNC_V(xrSyncActions); + OPENXR_API_INIT_XR_FUNC_V(xrWaitFrame); + OPENXR_API_INIT_XR_FUNC_V(xrWaitSwapchainImage); + + return true; +} + +XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) { + XrResult result = xrGetInstanceProcAddr(instance, p_name, p_addr); + + if (result != XR_SUCCESS) { + String error_message = String("Symbol ") + p_name + " not found in OpenXR instance."; + ERR_FAIL_COND_V_MSG(true, result, error_message.utf8().get_data()); + } + + return result; +} + bool OpenXRAPI::initialize(const String &p_rendering_driver) { ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created"); + if (!openxr_loader_init()) { + return false; + } + if (p_rendering_driver == "vulkan") { #ifdef VULKAN_ENABLED graphics_extension = memnew(OpenXRVulkanExtension(this)); @@ -1017,6 +1123,10 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { } // initialize + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_before_instance_created(); + } + if (!load_layer_properties()) { destroy_instance(); return false; @@ -1032,6 +1142,11 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { return false; } + if (!resolve_instance_openxr_symbols()) { + destroy_instance(); + return false; + } + if (!get_system_info()) { destroy_instance(); return false; @@ -1382,6 +1497,10 @@ void OpenXRAPI::pre_render() { // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible // This must thus be called as close to when we start rendering as possible XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr }; + frame_state.predictedDisplayTime = 0; + frame_state.predictedDisplayPeriod = 0; + frame_state.shouldRender = false; + XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state); if (XR_FAILED(result)) { print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]"); @@ -1643,7 +1762,10 @@ OpenXRAPI::OpenXRAPI() { #endif // register our other extensions + register_extension_wrapper(memnew(OpenXRPalmPoseExtension(this))); register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this))); + register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this))); + register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this))); } OpenXRAPI::~OpenXRAPI() { @@ -1669,6 +1791,13 @@ OpenXRAPI::~OpenXRAPI() { layer_properties = nullptr; } +#ifdef ANDROID_ENABLED + if (openxr_loader_library_handle) { + OS::get_singleton()->close_dynamic_library(openxr_loader_library_handle); + openxr_loader_library_handle = nullptr; + } +#endif + singleton = nullptr; } @@ -1745,6 +1874,18 @@ void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_l } } +bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const { + if (XR_SUCCEEDED(result)) + return true; + + char resultString[XR_MAX_RESULT_STRING_SIZE]; + xrResultToString(instance, result, resultString); + + print_error(String("OpenXR ") + String(format).format(args) + String(" [") + String(resultString) + String("]")); + + return false; +} + RID OpenXRAPI::get_tracker_rid(XrPath p_path) { List<RID> current; tracker_owner.get_owned_list(¤t); @@ -2063,6 +2204,11 @@ XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) { } RID OpenXRAPI::interaction_profile_create(const String p_name) { + if (!is_path_supported(p_name)) { + // The extension enabling this path must not be active, we will silently skip this interaction profile + return RID(); + } + InteractionProfile new_interaction_profile; XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_interaction_profile.path); @@ -2099,6 +2245,11 @@ void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) { } bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) { + if (!is_path_supported(p_path)) { + // The extension enabling this path must not be active, we will silently skip this binding + return false; + } + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); ERR_FAIL_NULL_V(ip, false); @@ -2426,3 +2577,11 @@ bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_freque return true; } + +void OpenXRAPI::register_composition_layer_provider(OpenXRCompositionLayerProvider *provider) { + composition_layer_providers.append(provider); +} + +void OpenXRAPI::unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider) { + composition_layer_providers.erase(provider); +} diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index dc224c4237..316886239e 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -36,6 +36,7 @@ #include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/os/memory.h" +#include "core/string/print_string.h" #include "core/string/ustring.h" #include "core/templates/rb_map.h" #include "core/templates/rid_owner.h" @@ -50,6 +51,8 @@ #include "extensions/openxr_composition_layer_provider.h" #include "extensions/openxr_extension_wrapper.h" +#include "util.h" + // Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initialising structs which ensures zeroing out unspecified members. // Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set. @@ -81,6 +84,8 @@ private: bool ext_vive_focus3_available = false; bool ext_huawei_controller_available = false; + bool is_path_supported(const String &p_path); + // composition layer providers Vector<OpenXRCompositionLayerProvider *> composition_layer_providers; @@ -100,7 +105,7 @@ private: XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE; - XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; + // XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; // state XrInstance instance = XR_NULL_HANDLE; @@ -134,6 +139,64 @@ private: bool load_supported_extensions(); bool is_extension_supported(const String &p_extension) const; + bool openxr_loader_init(); + bool resolve_instance_openxr_symbols(); + +#ifdef ANDROID_ENABLED + // On Android we keep tracker of our external OpenXR loader + void *openxr_loader_library_handle = nullptr; +#endif + + // function pointers +#ifdef ANDROID_ENABLED + // On non-Android platforms we use the OpenXR symbol linked into the engine binary. + PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr = nullptr; +#endif + EXT_PROTO_XRRESULT_FUNC3(xrAcquireSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageAcquireInfo *), acquireInfo, (uint32_t *), index) + EXT_PROTO_XRRESULT_FUNC3(xrApplyHapticFeedback, (XrSession), session, (const XrHapticActionInfo *), hapticActionInfo, (const XrHapticBaseHeader *), hapticFeedback) + EXT_PROTO_XRRESULT_FUNC2(xrAttachSessionActionSets, (XrSession), session, (const XrSessionActionSetsAttachInfo *), attachInfo) + EXT_PROTO_XRRESULT_FUNC2(xrBeginFrame, (XrSession), session, (const XrFrameBeginInfo *), frameBeginInfo) + EXT_PROTO_XRRESULT_FUNC2(xrBeginSession, (XrSession), session, (const XrSessionBeginInfo *), beginInfo) + EXT_PROTO_XRRESULT_FUNC3(xrCreateAction, (XrActionSet), actionSet, (const XrActionCreateInfo *), createInfo, (XrAction *), action) + EXT_PROTO_XRRESULT_FUNC3(xrCreateActionSet, (XrInstance), instance, (const XrActionSetCreateInfo *), createInfo, (XrActionSet *), actionSet) + EXT_PROTO_XRRESULT_FUNC3(xrCreateActionSpace, (XrSession), session, (const XrActionSpaceCreateInfo *), createInfo, (XrSpace *), space) + EXT_PROTO_XRRESULT_FUNC2(xrCreateInstance, (const XrInstanceCreateInfo *), createInfo, (XrInstance *), instance) + EXT_PROTO_XRRESULT_FUNC3(xrCreateReferenceSpace, (XrSession), session, (const XrReferenceSpaceCreateInfo *), createInfo, (XrSpace *), space) + EXT_PROTO_XRRESULT_FUNC3(xrCreateSession, (XrInstance), instance, (const XrSessionCreateInfo *), createInfo, (XrSession *), session) + EXT_PROTO_XRRESULT_FUNC3(xrCreateSwapchain, (XrSession), session, (const XrSwapchainCreateInfo *), createInfo, (XrSwapchain *), swapchain) + EXT_PROTO_XRRESULT_FUNC1(xrDestroyAction, (XrAction), action) + EXT_PROTO_XRRESULT_FUNC1(xrDestroyActionSet, (XrActionSet), actionSet) + EXT_PROTO_XRRESULT_FUNC1(xrDestroyInstance, (XrInstance), instance) + EXT_PROTO_XRRESULT_FUNC1(xrDestroySession, (XrSession), session) + EXT_PROTO_XRRESULT_FUNC1(xrDestroySpace, (XrSpace), space) + EXT_PROTO_XRRESULT_FUNC1(xrDestroySwapchain, (XrSwapchain), swapchain) + EXT_PROTO_XRRESULT_FUNC2(xrEndFrame, (XrSession), session, (const XrFrameEndInfo *), frameEndInfo) + EXT_PROTO_XRRESULT_FUNC1(xrEndSession, (XrSession), session) + EXT_PROTO_XRRESULT_FUNC3(xrEnumerateApiLayerProperties, (uint32_t), propertyCapacityInput, (uint32_t *), propertyCountOutput, (XrApiLayerProperties *), properties) + EXT_PROTO_XRRESULT_FUNC4(xrEnumerateInstanceExtensionProperties, (const char *), layerName, (uint32_t), propertyCapacityInput, (uint32_t *), propertyCountOutput, (XrExtensionProperties *), properties) + EXT_PROTO_XRRESULT_FUNC4(xrEnumerateReferenceSpaces, (XrSession), session, (uint32_t), spaceCapacityInput, (uint32_t *), spaceCountOutput, (XrReferenceSpaceType *), spaces) + EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainFormats, (XrSession), session, (uint32_t), formatCapacityInput, (uint32_t *), formatCountOutput, (int64_t *), formats) + EXT_PROTO_XRRESULT_FUNC5(xrEnumerateViewConfigurations, (XrInstance), instance, (XrSystemId), systemId, (uint32_t), viewConfigurationTypeCapacityInput, (uint32_t *), viewConfigurationTypeCountOutput, (XrViewConfigurationType *), viewConfigurationTypes) + EXT_PROTO_XRRESULT_FUNC6(xrEnumerateViewConfigurationViews, (XrInstance), instance, (XrSystemId), systemId, (XrViewConfigurationType), viewConfigurationType, (uint32_t), viewCapacityInput, (uint32_t *), viewCountOutput, (XrViewConfigurationView *), views) + EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateBoolean, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateBoolean *), state) + EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateFloat, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateFloat *), state) + EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateVector2f, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateVector2f *), state) + EXT_PROTO_XRRESULT_FUNC3(xrGetCurrentInteractionProfile, (XrSession), session, (XrPath), topLevelUserPath, (XrInteractionProfileState *), interactionProfile) + EXT_PROTO_XRRESULT_FUNC2(xrGetInstanceProperties, (XrInstance), instance, (XrInstanceProperties *), instanceProperties) + EXT_PROTO_XRRESULT_FUNC3(xrGetSystem, (XrInstance), instance, (const XrSystemGetInfo *), getInfo, (XrSystemId *), systemId) + EXT_PROTO_XRRESULT_FUNC3(xrGetSystemProperties, (XrInstance), instance, (XrSystemId), systemId, (XrSystemProperties *), properties) + EXT_PROTO_XRRESULT_FUNC4(xrLocateSpace, (XrSpace), space, (XrSpace), baseSpace, (XrTime), time, (XrSpaceLocation *), location) + EXT_PROTO_XRRESULT_FUNC6(xrLocateViews, (XrSession), session, (const XrViewLocateInfo *), viewLocateInfo, (XrViewState *), viewState, (uint32_t), viewCapacityInput, (uint32_t *), viewCountOutput, (XrView *), views) + EXT_PROTO_XRRESULT_FUNC5(xrPathToString, (XrInstance), instance, (XrPath), path, (uint32_t), bufferCapacityInput, (uint32_t *), bufferCountOutput, (char *), buffer) + EXT_PROTO_XRRESULT_FUNC2(xrPollEvent, (XrInstance), instance, (XrEventDataBuffer *), eventData) + EXT_PROTO_XRRESULT_FUNC2(xrReleaseSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageReleaseInfo *), releaseInfo) + EXT_PROTO_XRRESULT_FUNC3(xrResultToString, (XrInstance), instance, (XrResult), value, (char *), buffer) + EXT_PROTO_XRRESULT_FUNC3(xrStringToPath, (XrInstance), instance, (const char *), pathString, (XrPath *), path) + EXT_PROTO_XRRESULT_FUNC2(xrSuggestInteractionProfileBindings, (XrInstance), instance, (const XrInteractionProfileSuggestedBinding *), suggestedBindings) + EXT_PROTO_XRRESULT_FUNC2(xrSyncActions, (XrSession), session, (const XrActionsSyncInfo *), syncInfo) + EXT_PROTO_XRRESULT_FUNC3(xrWaitFrame, (XrSession), session, (const XrFrameWaitInfo *), frameWaitInfo, (XrFrameState *), frameState) + EXT_PROTO_XRRESULT_FUNC2(xrWaitSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageWaitInfo *), waitInfo) + // instance bool create_instance(); bool get_system_info(); @@ -212,9 +275,7 @@ private: // convencience void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len); -protected: - friend class OpenXRVulkanExtension; - +public: XrInstance get_instance() const { return instance; }; XrSystemId get_system_id() const { return system_id; }; XrSession get_session() const { return session; }; @@ -227,10 +288,12 @@ protected: XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform); void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); -public: + bool xr_result(XrResult result, const char *format, Array args = Array()) const; + static bool openxr_is_enabled(bool p_check_run_in_editor = true); static OpenXRAPI *get_singleton(); + XrResult get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr); String get_error_string(XrResult result); String get_swapchain_format_name(int64_t p_swapchain_format) const; @@ -243,8 +306,9 @@ public: bool initialize_session(); void finish(); - XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; }; - bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; }; + XrSpace get_play_space() const { return play_space; } + XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; } + bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; } Size2 get_recommended_target_size(); XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); @@ -288,6 +352,9 @@ public: XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); bool trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns); + void register_composition_layer_provider(OpenXRCompositionLayerProvider *provider); + void unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider); + OpenXRAPI(); ~OpenXRAPI(); }; diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 6c2f08e21d..01e148e00f 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -176,33 +176,35 @@ void OpenXRInterface::_load_action_map() { // Note, we can only have one entry per interaction profile so if it already exists we clear it out RID ip = openxr_api->interaction_profile_create(xr_interaction_profile->get_interaction_profile_path()); - openxr_api->interaction_profile_clear_bindings(ip); - - Array xr_bindings = xr_interaction_profile->get_bindings(); - for (int j = 0; j < xr_bindings.size(); j++) { - Ref<OpenXRIPBinding> xr_binding = xr_bindings[j]; - Ref<OpenXRAction> xr_action = xr_binding->get_action(); - - Action *action = nullptr; - if (xr_actions.has(xr_action)) { - action = xr_actions[xr_action]; - } else { - print_line("Action ", xr_action->get_name(), " isn't part of an action set!"); - continue; - } + if (ip.is_valid()) { + openxr_api->interaction_profile_clear_bindings(ip); + + Array xr_bindings = xr_interaction_profile->get_bindings(); + for (int j = 0; j < xr_bindings.size(); j++) { + Ref<OpenXRIPBinding> xr_binding = xr_bindings[j]; + Ref<OpenXRAction> xr_action = xr_binding->get_action(); + + Action *action = nullptr; + if (xr_actions.has(xr_action)) { + action = xr_actions[xr_action]; + } else { + print_line("Action ", xr_action->get_name(), " isn't part of an action set!"); + continue; + } - PackedStringArray paths = xr_binding->get_paths(); - for (int k = 0; k < paths.size(); k++) { - openxr_api->interaction_profile_add_binding(ip, action->action_rid, paths[k]); + PackedStringArray paths = xr_binding->get_paths(); + for (int k = 0; k < paths.size(); k++) { + openxr_api->interaction_profile_add_binding(ip, action->action_rid, paths[k]); + } } - } - // Now submit our suggestions - openxr_api->interaction_profile_suggest_bindings(ip); + // Now submit our suggestions + openxr_api->interaction_profile_suggest_bindings(ip); - // And record it in our array so we can clean it up later on - if (interaction_profiles.has(ip)) { - interaction_profiles.push_back(ip); + // And record it in our array so we can clean it up later on + if (interaction_profiles.has(ip)) { + interaction_profiles.push_back(ip); + } } } } @@ -744,6 +746,24 @@ void OpenXRInterface::end_frame() { } } +bool OpenXRInterface::is_passthrough_supported() { + return passthrough_wrapper != nullptr && passthrough_wrapper->is_passthrough_supported(); +} + +bool OpenXRInterface::is_passthrough_enabled() { + return passthrough_wrapper != nullptr && passthrough_wrapper->is_passthrough_enabled(); +} + +bool OpenXRInterface::start_passthrough() { + return passthrough_wrapper != nullptr && passthrough_wrapper->start_passthrough(); +} + +void OpenXRInterface::stop_passthrough() { + if (passthrough_wrapper) { + passthrough_wrapper->stop_passthrough(); + } +} + void OpenXRInterface::on_state_ready() { emit_signal(SNAME("session_begun")); } @@ -774,6 +794,8 @@ OpenXRInterface::OpenXRInterface() { _set_default_pos(head_transform, 1.0, 0); _set_default_pos(transform_for_view[0], 1.0, 1); _set_default_pos(transform_for_view[1], 1.0, 2); + + passthrough_wrapper = OpenXRFbPassthroughExtensionWrapper::get_singleton(); } OpenXRInterface::~OpenXRInterface() { diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index a99012fd1d..3765f18637 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -37,6 +37,8 @@ #include "action_map/openxr_action_map.h" #include "openxr_api.h" +#include "extensions/openxr_fb_passthrough_extension_wrapper.h" + // declare some default strings #define INTERACTION_PROFILE_NONE "/interaction_profiles/none" @@ -47,6 +49,7 @@ private: OpenXRAPI *openxr_api = nullptr; bool initialized = false; XRInterface::TrackingStatus tracking_state; + OpenXRFbPassthroughExtensionWrapper *passthrough_wrapper = nullptr; // At a minimum we need a tracker for our head Ref<XRPositionalTracker> head; @@ -129,6 +132,11 @@ public: virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void end_frame() override; + virtual bool is_passthrough_supported() override; + virtual bool is_passthrough_enabled() override; + virtual bool start_passthrough() override; + virtual void stop_passthrough() override; + void on_state_ready(); void on_state_visible(); void on_state_focused(); diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index c765f169dc..5694fffe39 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -38,6 +38,8 @@ #include "action_map/openxr_action_set.h" #include "action_map/openxr_interaction_profile.h" +#include "scene/openxr_hand.h" + #ifdef TOOLS_ENABLED #include "editor/editor_node.h" @@ -82,6 +84,8 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(OpenXRIPBinding); GDREGISTER_CLASS(OpenXRInteractionProfile); + GDREGISTER_CLASS(OpenXRHand); + XRServer *xr_server = XRServer::get_singleton(); if (xr_server) { openxr_interface.instantiate(); diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp new file mode 100644 index 0000000000..2ae13a1026 --- /dev/null +++ b/modules/openxr/scene/openxr_hand.cpp @@ -0,0 +1,307 @@ +/*************************************************************************/ +/* openxr_hand.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 "../extensions/openxr_hand_tracking_extension.h" +#include "../openxr_api.h" + +#include "openxr_hand.h" +#include "scene/3d/skeleton_3d.h" +#include "servers/xr_server.h" + +void OpenXRHand::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_hand", "hand"), &OpenXRHand::set_hand); + ClassDB::bind_method(D_METHOD("get_hand"), &OpenXRHand::get_hand); + + ClassDB::bind_method(D_METHOD("set_hand_skeleton", "hand_skeleton"), &OpenXRHand::set_hand_skeleton); + ClassDB::bind_method(D_METHOD("get_hand_skeleton"), &OpenXRHand::get_hand_skeleton); + + ClassDB::bind_method(D_METHOD("set_motion_range", "motion_range"), &OpenXRHand::set_motion_range); + ClassDB::bind_method(D_METHOD("get_motion_range"), &OpenXRHand::get_motion_range); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton"); + + BIND_ENUM_CONSTANT(HAND_LEFT); + BIND_ENUM_CONSTANT(HAND_RIGHT); + BIND_ENUM_CONSTANT(HAND_MAX); + + BIND_ENUM_CONSTANT(MOTION_RANGE_UNOBSTRUCTED); + BIND_ENUM_CONSTANT(MOTION_RANGE_CONFORM_TO_CONTROLLER); + BIND_ENUM_CONSTANT(MOTION_RANGE_MAX); +} + +OpenXRHand::OpenXRHand() { + openxr_api = OpenXRAPI::get_singleton(); + hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); +} + +void OpenXRHand::set_hand(const Hands p_hand) { + ERR_FAIL_INDEX(p_hand, HAND_MAX); + + hand = p_hand; +} + +OpenXRHand::Hands OpenXRHand::get_hand() const { + return hand; +} + +void OpenXRHand::set_hand_skeleton(const NodePath &p_hand_skeleton) { + hand_skeleton = p_hand_skeleton; + + // TODO if inside tree call _get_bones() +} + +void OpenXRHand::set_motion_range(const MotionRange p_motion_range) { + ERR_FAIL_INDEX(p_motion_range, MOTION_RANGE_MAX); + motion_range = p_motion_range; + + _set_motion_range(); +} + +OpenXRHand::MotionRange OpenXRHand::get_motion_range() const { + return motion_range; +} + +NodePath OpenXRHand::get_hand_skeleton() const { + return hand_skeleton; +} + +void OpenXRHand::_set_motion_range() { + if (!hand_tracking_ext) { + return; + } + + XrHandJointsMotionRangeEXT xr_motion_range; + switch (motion_range) { + case MOTION_RANGE_UNOBSTRUCTED: + xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; + break; + case MOTION_RANGE_CONFORM_TO_CONTROLLER: + xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT; + break; + default: + xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT; + break; + } + + hand_tracking_ext->set_motion_range(hand, xr_motion_range); +} + +Skeleton3D *OpenXRHand::get_skeleton() { + if (!has_node(hand_skeleton)) { + return nullptr; + } + + Node *node = get_node(hand_skeleton); + if (!node) { + return nullptr; + } + + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); + return skeleton; +} + +void OpenXRHand::_get_bones() { + const char *bone_names[XR_HAND_JOINT_COUNT_EXT] = { + "Palm", + "Wrist", + "Thumb_Metacarpal", + "Thumb_Proximal", + "Thumb_Distal", + "Thumb_Tip", + "Index_Metacarpal", + "Index_Proximal", + "Index_Intermediate", + "Index_Distal", + "Index_Tip", + "Middle_Metacarpal", + "Middle_Proximal", + "Middle_Intermediate", + "Middle_Distal", + "Middle_Tip", + "Ring_Metacarpal", + "Ring_Proximal", + "Ring_Intermediate", + "Ring_Distal", + "Ring_Tip", + "Little_Metacarpal", + "Little_Proximal", + "Little_Intermediate", + "Little_Distal", + "Little_Tip", + }; + + // reset JIC + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + bones[i] = -1; + } + + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + + // We cast to spatials which should allow us to use any subclass of that. + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + String bone_name = bone_names[i]; + if (hand == 0) { + bone_name += String("_L"); + } else { + bone_name += String("_R"); + } + + bones[i] = skeleton->find_bone(bone_name); + if (bones[i] == -1) { + print_line("Couldn't obtain bone for", bone_name); + } + } +} + +void OpenXRHand::_update_skeleton() { + if (openxr_api == nullptr || !openxr_api->is_initialized()) { + return; + } else if (hand_tracking_ext == nullptr || !hand_tracking_ext->get_active()) { + return; + } + + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + + // we cache our transforms so we can quickly calculate local transforms + XRPose::TrackingConfidence confidences[XR_HAND_JOINT_COUNT_EXT]; + Quaternion quaternions[XR_HAND_JOINT_COUNT_EXT]; + Quaternion inv_quaternions[XR_HAND_JOINT_COUNT_EXT]; + Vector3 positions[XR_HAND_JOINT_COUNT_EXT]; + + const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(hand); + const float ws = XRServer::get_singleton()->get_world_scale(); + + if (hand_tracker->is_initialised && hand_tracker->locations.isActive) { + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_NONE; + quaternions[i] = Quaternion(); + positions[i] = Vector3(); + + const auto &location = hand_tracker->joint_locations[i]; + const auto &pose = location.pose; + + if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { + if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.y != 0 || pose.orientation.w != 0) { + quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w); + inv_quaternions[i] = quaternions[i].inverse(); + + if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { + confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_HIGH; + positions[i] = Vector3(pose.position.x * ws, pose.position.y * ws, pose.position.z * ws); + + // TODO get inverse of position, we'll do this later. For now we're ignoring bone positions which generally works better anyway + } else { + confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_LOW; + } + } + } + } + + if (confidences[XR_HAND_JOINT_PALM_EXT] != XRPose::XR_TRACKING_CONFIDENCE_NONE) { + // now update our skeleton + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + if (bones[i] != -1) { + int bone = bones[i]; + int parent = skeleton->get_bone_parent(bone); + + // Get our target quaternion + Quaternion q = quaternions[i]; + + // get local translation, parent should already be processed + if (parent == -1) { + // use our palm location here, that is what we are tracking + q = inv_quaternions[XR_HAND_JOINT_PALM_EXT] * q; + } else { + int found = false; + for (int b = 0; b < XR_HAND_JOINT_COUNT_EXT && !found; b++) { + if (bones[b] == parent) { + q = inv_quaternions[b] * q; + found = true; + } + } + } + + // And get the movement from our rest position + // Transform3D rest = skeleton->get_bone_rest(bones[i]); + // q = rest.basis.get_quaternion().inverse() * q; + + // and set our pose + // skeleton->set_bone_pose_position(bones[i], v); + skeleton->set_bone_pose_rotation(bones[i], q); + } + } + + Transform3D t; + t.basis = Basis(quaternions[XR_HAND_JOINT_PALM_EXT]); + t.origin = positions[XR_HAND_JOINT_PALM_EXT]; + set_transform(t); + + // show it + set_visible(true); + } else { + // hide it + set_visible(false); + } + } else { + // hide it + set_visible(false); + } +} + +void OpenXRHand::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _get_bones(); + + set_process_internal(true); + } break; + case NOTIFICATION_EXIT_TREE: { + set_process_internal(false); + + // reset + for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { + bones[i] = -1; + } + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + _update_skeleton(); + } break; + default: { + } break; + } +} diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h new file mode 100644 index 0000000000..f8499cc172 --- /dev/null +++ b/modules/openxr/scene/openxr_hand.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* openxr_hand.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_HAND_H +#define OPENXR_HAND_H + +#include "scene/3d/node_3d.h" +#include "scene/3d/skeleton_3d.h" + +class OpenXRAPI; +class OpenXRHandTrackingExtension; + +class OpenXRHand : public Node3D { + GDCLASS(OpenXRHand, Node3D); + +public: + enum Hands { + HAND_LEFT, + HAND_RIGHT, + HAND_MAX + }; + + enum MotionRange { + MOTION_RANGE_UNOBSTRUCTED, + MOTION_RANGE_CONFORM_TO_CONTROLLER, + MOTION_RANGE_MAX + }; + +private: + OpenXRAPI *openxr_api = nullptr; + OpenXRHandTrackingExtension *hand_tracking_ext = nullptr; + + Hands hand = HAND_LEFT; + MotionRange motion_range = MOTION_RANGE_UNOBSTRUCTED; + NodePath hand_skeleton; + + int64_t bones[XR_HAND_JOINT_COUNT_EXT]; + + void _set_motion_range(); + + Skeleton3D *get_skeleton(); + void _get_bones(); + void _update_skeleton(); + +protected: + static void _bind_methods(); + +public: + OpenXRHand(); + + void set_hand(const Hands p_hand); + Hands get_hand() const; + + void set_motion_range(const MotionRange p_motion_range); + MotionRange get_motion_range() const; + + void set_hand_skeleton(const NodePath &p_hand_skeleton); + NodePath get_hand_skeleton() const; + + void _notification(int p_what); +}; + +VARIANT_ENUM_CAST(OpenXRHand::Hands) +VARIANT_ENUM_CAST(OpenXRHand::MotionRange) + +#endif // OPENXR_HAND_H diff --git a/modules/openxr/util.h b/modules/openxr/util.h new file mode 100644 index 0000000000..5c79890830 --- /dev/null +++ b/modules/openxr/util.h @@ -0,0 +1,110 @@ +/*************************************************************************/ +/* util.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 UTIL_H +#define UTIL_H + +#define UNPACK(...) __VA_ARGS__ + +#define INIT_XR_FUNC_V(openxr_api, name) \ + do { \ + XrResult get_instance_proc_addr_result; \ + get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \ + ERR_FAIL_COND_V(XR_FAILED(get_instance_proc_addr_result), false); \ + } while (0) + +#define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(openxr_api, name) +#define OPENXR_API_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(this, name) + +#define INIT_XR_FUNC(openxr_api, name) \ + do { \ + XrResult get_instance_proc_addr_result; \ + get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \ + ERR_FAIL_COND(XR_FAILED(get_instance_proc_addr_result)); \ + } while (0) + +#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(openxr_api, name) +#define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name) + +#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \ + PFN_##func_name func_name##_ptr = nullptr; \ + XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1) const { \ + if (!func_name##_ptr) { \ + return XR_ERROR_HANDLE_INVALID; \ + } \ + return (*func_name##_ptr)(arg1); \ + } + +#define EXT_PROTO_XRRESULT_FUNC2(func_name, arg1_type, arg1, arg2_type, arg2) \ + PFN_##func_name func_name##_ptr = nullptr; \ + XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2) const { \ + if (!func_name##_ptr) { \ + return XR_ERROR_HANDLE_INVALID; \ + } \ + return (*func_name##_ptr)(arg1, arg2); \ + } + +#define EXT_PROTO_XRRESULT_FUNC3(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3) \ + PFN_##func_name func_name##_ptr = nullptr; \ + XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3) const { \ + if (!func_name##_ptr) { \ + return XR_ERROR_HANDLE_INVALID; \ + } \ + return (*func_name##_ptr)(arg1, arg2, arg3); \ + } + +#define EXT_PROTO_XRRESULT_FUNC4(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4) \ + PFN_##func_name func_name##_ptr = nullptr; \ + XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4) const { \ + if (!func_name##_ptr) { \ + return XR_ERROR_HANDLE_INVALID; \ + } \ + return (*func_name##_ptr)(arg1, arg2, arg3, arg4); \ + } + +#define EXT_PROTO_XRRESULT_FUNC5(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5) \ + PFN_##func_name func_name##_ptr = nullptr; \ + XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4, UNPACK arg5_type arg5) const { \ + if (!func_name##_ptr) { \ + return XR_ERROR_HANDLE_INVALID; \ + } \ + return (*func_name##_ptr)(arg1, arg2, arg3, arg4, arg5); \ + } + +#define EXT_PROTO_XRRESULT_FUNC6(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5, arg6_type, arg6) \ + PFN_##func_name func_name##_ptr = nullptr; \ + XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4, UNPACK arg5_type arg5, UNPACK arg6_type arg6) const { \ + if (!func_name##_ptr) { \ + return XR_ERROR_HANDLE_INVALID; \ + } \ + return (*func_name##_ptr)(arg1, arg2, arg3, arg4, arg5, arg6); \ + } + +#endif // UTIL_H diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub index 074795759a..20b05816e1 100644 --- a/modules/raycast/SCsub +++ b/modules/raycast/SCsub @@ -63,7 +63,8 @@ if env["builtin_embree"]: thirdparty_sources = [thirdparty_dir + file for file in embree_src] env_raycast.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "include"]) - env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"]) + env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL"]) + env_raycast.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds. if not env.msvc: if env["arch"] == "x86_64": @@ -78,6 +79,9 @@ if env["builtin_embree"]: else: env.Append(LIBS=["psapi"]) + if env.msvc: # Disable bogus warning about intentional struct padding. + env_raycast.Append(CCFLAGS=["/wd4324"]) + env_thirdparty = env_raycast.Clone() env_thirdparty.force_optimization_on_debug() env_thirdparty.disable_warnings() diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster_embree.cpp index 9b35b5616e..e6a579bd3a 100644 --- a/modules/raycast/lightmap_raycaster.cpp +++ b/modules/raycast/lightmap_raycaster_embree.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* lightmap_raycaster.cpp */ +/* lightmap_raycaster_embree.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #ifdef TOOLS_ENABLED -#include "lightmap_raycaster.h" +#include "lightmap_raycaster_embree.h" #ifdef __SSE2__ #include <pmmintrin.h> @@ -193,4 +193,4 @@ LightmapRaycasterEmbree::~LightmapRaycasterEmbree() { } } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster_embree.h index 2e9f59dda4..0c3371f07c 100644 --- a/modules/raycast/lightmap_raycaster.h +++ b/modules/raycast/lightmap_raycaster_embree.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* lightmap_raycaster.h */ +/* lightmap_raycaster_embree.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef LIGHTMAP_RAYCASTER_EMBREE_H +#define LIGHTMAP_RAYCASTER_EMBREE_H + #ifdef TOOLS_ENABLED #include "core/io/image.h" @@ -74,4 +77,6 @@ public: ~LightmapRaycasterEmbree(); }; -#endif // LIGHTMAP_RAYCASTER_H +#endif // TOOLS_ENABLED + +#endif // LIGHTMAP_RAYCASTER_EMBREE_H diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp index 42de1d971d..a8380b00ba 100644 --- a/modules/raycast/register_types.cpp +++ b/modules/raycast/register_types.cpp @@ -30,9 +30,9 @@ #include "register_types.h" -#include "lightmap_raycaster.h" +#include "lightmap_raycaster_embree.h" #include "raycast_occlusion_cull.h" -#include "static_raycaster.h" +#include "static_raycaster_embree.h" RaycastOcclusionCull *raycast_occlusion_cull = nullptr; diff --git a/modules/raycast/register_types.h b/modules/raycast/register_types.h index a917285390..25a6c346b9 100644 --- a/modules/raycast/register_types.h +++ b/modules/raycast/register_types.h @@ -28,7 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef RAYCAST_REGISTER_TYPES_H +#define RAYCAST_REGISTER_TYPES_H + #include "modules/register_module_types.h" void initialize_raycast_module(ModuleInitializationLevel p_level); void uninitialize_raycast_module(ModuleInitializationLevel p_level); + +#endif // RAYCAST_REGISTER_TYPES_H diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster_embree.cpp index 7659eea27f..b5a4ab42d4 100644 --- a/modules/raycast/static_raycaster.cpp +++ b/modules/raycast/static_raycaster_embree.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* static_raycaster.cpp */ +/* static_raycaster_embree.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #ifdef TOOLS_ENABLED -#include "static_raycaster.h" +#include "static_raycaster_embree.h" #ifdef __SSE2__ #include <pmmintrin.h> @@ -134,4 +134,4 @@ StaticRaycasterEmbree::~StaticRaycasterEmbree() { } } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster_embree.h index 607a392683..4d631e3ca0 100644 --- a/modules/raycast/static_raycaster.h +++ b/modules/raycast/static_raycaster_embree.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* static_raycaster.h */ +/* static_raycaster_embree.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef STATIC_RAYCASTER_EMBREE_H +#define STATIC_RAYCASTER_EMBREE_H + #ifdef TOOLS_ENABLED #include "core/math/static_raycaster.h" @@ -61,4 +64,6 @@ public: ~StaticRaycasterEmbree(); }; -#endif // STATIC_RAYCASTER_H +#endif // TOOLS_ENABLED + +#endif // STATIC_RAYCASTER_EMBREE_H diff --git a/modules/regex/SCsub b/modules/regex/SCsub index deb9db7591..6fd7cd47f3 100644 --- a/modules/regex/SCsub +++ b/modules/regex/SCsub @@ -58,10 +58,10 @@ if env["builtin_pcre2"]: env_pcre2["OBJSUFFIX"] = "_" + width + env_pcre2["OBJSUFFIX"] env_pcre2.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", width)]) env_pcre2.add_source_files(thirdparty_obj, thirdparty_sources) - env.modules_sources += thirdparty_obj pcre2_builtin("16") pcre2_builtin("32") + env.modules_sources += thirdparty_obj # Godot source files diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 8d0245f0f6..2261342467 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -215,6 +215,9 @@ if env["builtin_graphite"] and freetype_enabled and env["graphite"]: ] ) + if env.msvc: # Not our business to fix. + env_graphite.Append(CCFLAGS=["-D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS"]) + lib = env_graphite.add_library("graphite_builtin", thirdparty_sources) thirdparty_obj += lib @@ -445,7 +448,7 @@ if env["builtin_icu"]: icu_data_name = "icudt71l.dat" - if env_icu["tools"]: + if env.editor_build: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) env_icu.Command("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name, make_icu_data) env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/"]) @@ -479,7 +482,7 @@ if env["builtin_icu"]: "-DICU_DATA_NAME=" + icu_data_name, ] ) - if env_text_server_adv["tools"]: + if env.editor_build: env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"]) env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"]) diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 0170c007ae..7ca8859ee6 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -19,6 +19,7 @@ env = SConscript("./godot-cpp/SConstruct") env.__class__.disable_warnings = methods.disable_warnings opts = Variables([], ARGUMENTS) +opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True)) opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True)) opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True)) opts.Add(BoolVariable("graphite_enabled", "Use Graphite library (require FreeType)", True)) @@ -162,6 +163,25 @@ if env["freetype_enabled"]: ] thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources] + if env["brotli_enabled"]: + thirdparty_brotli_dir = "../../../thirdparty/brotli/" + thirdparty_brotli_sources = [ + "common/constants.c", + "common/context.c", + "common/dictionary.c", + "common/platform.c", + "common/shared_dictionary.c", + "common/transform.c", + "dec/bit_reader.c", + "dec/decode.c", + "dec/huffman.c", + "dec/state.c", + ] + thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] + env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) + env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir]) env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"]) @@ -173,7 +193,7 @@ if env["freetype_enabled"]: "FT_CONFIG_OPTION_SYSTEM_ZLIB", ] ) - if env["target"] == "debug": + if env.dev_build: env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) @@ -265,6 +285,7 @@ env_harfbuzz.Append( CPPPATH=[ "../../../thirdparty/harfbuzz/src", "../../../thirdparty/icu4c/common/", + "../../../thirdparty/icu4c/i18n/", ] ) @@ -569,6 +590,10 @@ thirdparty_icu_sources = [ "common/uvectr32.cpp", "common/uvectr64.cpp", "common/wintz.cpp", + "i18n/scriptset.cpp", + "i18n/ucln_in.cpp", + "i18n/uspoof.cpp", + "i18n/uspoof_impl.cpp", ] thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources] @@ -584,7 +609,7 @@ if env["static_icu_data"]: else: thirdparty_sources += ["../icu_data/icudata_stub.cpp"] -env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/"]) +env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"]) env_icu.Append( CXXFLAGS=[ "-DU_STATIC_IMPLEMENTATION", @@ -610,7 +635,7 @@ env.Append( "-DICU_DATA_NAME=" + icu_data_name, ] ) -env.Append(CPPPATH=["../../../thirdparty/icu4c/common/"]) +env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"]) if env["platform"] == "windows": env.Append(LIBS=["advapi32"]) diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index c128374be1..d0301eeae3 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -33,7 +33,7 @@ #ifdef GDEXTENSION // Headers for building as GDExtension plug-in. -#include <godot_cpp/classes/file.hpp> +#include <godot_cpp/classes/file_access.hpp> #include <godot_cpp/classes/project_settings.hpp> #include <godot_cpp/classes/rendering_server.hpp> #include <godot_cpp/classes/translation_server.hpp> @@ -327,7 +327,7 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) { /*************************************************************************/ -bool TextServerAdvanced::has_feature(Feature p_feature) const { +bool TextServerAdvanced::_has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_SIMPLE_LAYOUT: case FEATURE_BIDI_LAYOUT: @@ -354,7 +354,7 @@ bool TextServerAdvanced::has_feature(Feature p_feature) const { return false; } -String TextServerAdvanced::get_name() const { +String TextServerAdvanced::_get_name() const { #ifdef GDEXTENSION return "ICU / HarfBuzz / Graphite (GDExtension)"; #else @@ -362,7 +362,7 @@ String TextServerAdvanced::get_name() const { #endif } -int64_t TextServerAdvanced::get_features() const { +int64_t TextServerAdvanced::_get_features() const { int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA; #ifdef MODULE_FREETYPE_ENABLED interface_features |= FEATURE_FONT_DYNAMIC; @@ -374,7 +374,7 @@ int64_t TextServerAdvanced::get_features() const { return interface_features; } -void TextServerAdvanced::free_rid(const RID &p_rid) { +void TextServerAdvanced::_free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontAdvanced *fd = font_owner.get_or_null(p_rid); @@ -387,12 +387,12 @@ void TextServerAdvanced::free_rid(const RID &p_rid) { } } -bool TextServerAdvanced::has(const RID &p_rid) { +bool TextServerAdvanced::_has(const RID &p_rid) { _THREAD_SAFE_METHOD_ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid); } -bool TextServerAdvanced::load_support_data(const String &p_filename) { +bool TextServerAdvanced::_load_support_data(const String &p_filename) { _THREAD_SAFE_METHOD_ #ifdef ICU_STATIC_DATA @@ -410,7 +410,11 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { return false; } uint64_t len = f->get_length(); +#ifdef GDEXTENSION + PackedByteArray icu_data = f->get_buffer(len); +#else PackedByteArray icu_data = f->_get_buffer(len); +#endif UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -429,7 +433,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { return true; } -String TextServerAdvanced::get_support_data_filename() const { +String TextServerAdvanced::_get_support_data_filename() const { #ifdef ICU_STATIC_DATA return _MKSTR(ICU_DATA_NAME); #else @@ -437,7 +441,7 @@ String TextServerAdvanced::get_support_data_filename() const { #endif } -String TextServerAdvanced::get_support_data_info() const { +String TextServerAdvanced::_get_support_data_info() const { #ifdef ICU_STATIC_DATA return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); #else @@ -445,7 +449,7 @@ String TextServerAdvanced::get_support_data_info() const { #endif } -bool TextServerAdvanced::save_support_data(const String &p_filename) const { +bool TextServerAdvanced::_save_support_data(const String &p_filename) const { _THREAD_SAFE_METHOD_ #ifdef ICU_STATIC_DATA @@ -459,7 +463,11 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { PackedByteArray icu_data; icu_data.resize(U_ICUDATA_SIZE); memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); +#ifdef GDEXTENSION + f->store_buffer(icu_data); +#else f->_store_buffer(icu_data); +#endif return true; #else @@ -467,7 +475,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { #endif } -bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const { +bool TextServerAdvanced::_is_locale_right_to_left(const String &p_locale) const { String l = p_locale.get_slicec('_', 0); if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) { return true; @@ -739,7 +747,7 @@ void TextServerAdvanced::_insert_feature_sets() { _insert_feature("weight", HB_TAG('w', 'g', 'h', 't'), Variant::Type::INT, false); } -int64_t TextServerAdvanced::name_to_tag(const String &p_name) const { +int64_t TextServerAdvanced::_name_to_tag(const String &p_name) const { if (feature_sets.has(p_name)) { return feature_sets[p_name]; } @@ -762,7 +770,7 @@ bool TextServerAdvanced::_get_tag_hidden(int64_t p_tag) const { return false; } -String TextServerAdvanced::tag_to_name(int64_t p_tag) const { +String TextServerAdvanced::_tag_to_name(int64_t p_tag) const { if (feature_sets_inv.has(p_tag)) { return feature_sets_inv[p_tag].name; } @@ -1043,8 +1051,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( td.projection = &projection; td.distancePixelConversion = &distancePixelConversion; +#ifdef GDEXTENSION + for (int i = 0; i < h; i++) { + _generateMTSDF_threaded(i, &td); + } +#else WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, SNAME("FontServerRasterizeMSDF")); WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); +#endif msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); @@ -1415,7 +1429,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f fd->oversampling = 1.0; fd->size.x = p_font_data->msdf_source_size; } else if (p_font_data->oversampling <= 0.0) { - fd->oversampling = font_get_global_oversampling(); + fd->oversampling = _font_get_global_oversampling(); } else { fd->oversampling = p_font_data->oversampling; } @@ -1808,8 +1822,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } - if (p_font_data->variation_coordinates.has(tag_to_name(var.tag))) { - var.value = p_font_data->variation_coordinates[tag_to_name(var.tag)]; + if (p_font_data->variation_coordinates.has(_tag_to_name(var.tag))) { + var.value = p_font_data->variation_coordinates[_tag_to_name(var.tag)]; coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } @@ -1854,7 +1868,7 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_ return fd->cache[size]->hb_handle; } -RID TextServerAdvanced::create_font() { +RID TextServerAdvanced::_create_font() { _THREAD_SAFE_METHOD_ FontAdvanced *fd = memnew(FontAdvanced); @@ -1862,7 +1876,7 @@ RID TextServerAdvanced::create_font() { return font_owner.make_rid(fd); } -void TextServerAdvanced::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { +void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1873,7 +1887,7 @@ void TextServerAdvanced::font_set_data(const RID &p_font_rid, const PackedByteAr fd->data_size = fd->data.size(); } -void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { +void TextServerAdvanced::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1884,7 +1898,7 @@ void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t fd->data_size = p_data_size; } -void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { +void TextServerAdvanced::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { ERR_FAIL_COND(p_face_index < 0); ERR_FAIL_COND(p_face_index >= 0x7FFF); @@ -1898,7 +1912,7 @@ void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_fa } } -int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_face_index(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1906,7 +1920,7 @@ int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const { return fd->face_index; } -int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1947,7 +1961,7 @@ int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { return face_count; } -void TextServerAdvanced::font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) { +void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1957,7 +1971,7 @@ void TextServerAdvanced::font_set_style(const RID &p_font_rid, BitField<FontStyl fd->style_flags = p_style; } -BitField<TextServer::FontStyle> TextServerAdvanced::font_get_style(const RID &p_font_rid) const { +BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1967,7 +1981,7 @@ BitField<TextServer::FontStyle> TextServerAdvanced::font_get_style(const RID &p_ return fd->style_flags; } -void TextServerAdvanced::font_set_style_name(const RID &p_font_rid, const String &p_name) { +void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const String &p_name) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1977,7 +1991,7 @@ void TextServerAdvanced::font_set_style_name(const RID &p_font_rid, const String fd->style_name = p_name; } -String TextServerAdvanced::font_get_style_name(const RID &p_font_rid) const { +String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1987,7 +2001,7 @@ String TextServerAdvanced::font_get_style_name(const RID &p_font_rid) const { return fd->style_name; } -void TextServerAdvanced::font_set_name(const RID &p_font_rid, const String &p_name) { +void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1997,7 +2011,7 @@ void TextServerAdvanced::font_set_name(const RID &p_font_rid, const String &p_na fd->font_name = p_name; } -String TextServerAdvanced::font_get_name(const RID &p_font_rid) const { +String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -2007,7 +2021,7 @@ String TextServerAdvanced::font_get_name(const RID &p_font_rid) const { return fd->font_name; } -void TextServerAdvanced::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) { +void TextServerAdvanced::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2018,7 +2032,7 @@ void TextServerAdvanced::font_set_antialiasing(RID p_font_rid, TextServer::FontA } } -TextServer::FontAntialiasing TextServerAdvanced::font_get_antialiasing(RID p_font_rid) const { +TextServer::FontAntialiasing TextServerAdvanced::_font_get_antialiasing(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE); @@ -2026,7 +2040,7 @@ TextServer::FontAntialiasing TextServerAdvanced::font_get_antialiasing(RID p_fon return fd->antialiasing; } -void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { +void TextServerAdvanced::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2035,13 +2049,14 @@ void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p for (KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) { for (int i = 0; i < E.value->textures.size(); i++) { E.value->textures.write[i].dirty = true; + E.value->textures.write[i].texture = Ref<ImageTexture>(); } } fd->mipmaps = p_generate_mipmaps; } } -bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const { +bool TextServerAdvanced::_font_get_generate_mipmaps(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2049,7 +2064,7 @@ bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const return fd->mipmaps; } -void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { +void TextServerAdvanced::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2060,7 +2075,7 @@ void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID & } } -bool TextServerAdvanced::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { +bool TextServerAdvanced::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2068,7 +2083,7 @@ bool TextServerAdvanced::font_is_multichannel_signed_distance_field(const RID &p return fd->msdf; } -void TextServerAdvanced::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { +void TextServerAdvanced::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2079,7 +2094,7 @@ void TextServerAdvanced::font_set_msdf_pixel_range(const RID &p_font_rid, int64_ } } -int64_t TextServerAdvanced::font_get_msdf_pixel_range(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_msdf_pixel_range(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2087,7 +2102,7 @@ int64_t TextServerAdvanced::font_get_msdf_pixel_range(const RID &p_font_rid) con return fd->msdf_range; } -void TextServerAdvanced::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { +void TextServerAdvanced::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2098,7 +2113,7 @@ void TextServerAdvanced::font_set_msdf_size(const RID &p_font_rid, int64_t p_msd } } -int64_t TextServerAdvanced::font_get_msdf_size(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_msdf_size(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2106,7 +2121,7 @@ int64_t TextServerAdvanced::font_get_msdf_size(const RID &p_font_rid) const { return fd->msdf_source_size; } -void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { +void TextServerAdvanced::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2114,7 +2129,7 @@ void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi fd->fixed_size = p_fixed_size; } -int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2122,7 +2137,7 @@ int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const { return fd->fixed_size; } -void TextServerAdvanced::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { +void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2133,7 +2148,7 @@ void TextServerAdvanced::font_set_force_autohinter(const RID &p_font_rid, bool p } } -bool TextServerAdvanced::font_is_force_autohinter(const RID &p_font_rid) const { +bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2141,7 +2156,7 @@ bool TextServerAdvanced::font_is_force_autohinter(const RID &p_font_rid) const { return fd->force_autohinter; } -void TextServerAdvanced::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { +void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2152,7 +2167,7 @@ void TextServerAdvanced::font_set_hinting(const RID &p_font_rid, TextServer::Hin } } -TextServer::Hinting TextServerAdvanced::font_get_hinting(const RID &p_font_rid) const { +TextServer::Hinting TextServerAdvanced::_font_get_hinting(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, HINTING_NONE); @@ -2160,7 +2175,7 @@ TextServer::Hinting TextServerAdvanced::font_get_hinting(const RID &p_font_rid) return fd->hinting; } -void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { +void TextServerAdvanced::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2168,7 +2183,7 @@ void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, Te fd->subpixel_positioning = p_subpixel; } -TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(const RID &p_font_rid) const { +TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioning(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED); @@ -2176,7 +2191,7 @@ TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positionin return fd->subpixel_positioning; } -void TextServerAdvanced::font_set_embolden(const RID &p_font_rid, double p_strength) { +void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2187,7 +2202,7 @@ void TextServerAdvanced::font_set_embolden(const RID &p_font_rid, double p_stren } } -double TextServerAdvanced::font_get_embolden(const RID &p_font_rid) const { +double TextServerAdvanced::_font_get_embolden(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2195,7 +2210,7 @@ double TextServerAdvanced::font_get_embolden(const RID &p_font_rid) const { return fd->embolden; } -void TextServerAdvanced::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { +void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2206,7 +2221,7 @@ void TextServerAdvanced::font_set_transform(const RID &p_font_rid, const Transfo } } -Transform2D TextServerAdvanced::font_get_transform(const RID &p_font_rid) const { +Transform2D TextServerAdvanced::_font_get_transform(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Transform2D()); @@ -2214,7 +2229,7 @@ Transform2D TextServerAdvanced::font_get_transform(const RID &p_font_rid) const return fd->transform; } -void TextServerAdvanced::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { +void TextServerAdvanced::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2225,7 +2240,7 @@ void TextServerAdvanced::font_set_variation_coordinates(const RID &p_font_rid, c } } -Dictionary TextServerAdvanced::font_get_variation_coordinates(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_get_variation_coordinates(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2233,7 +2248,7 @@ Dictionary TextServerAdvanced::font_get_variation_coordinates(const RID &p_font_ return fd->variation_coordinates; } -void TextServerAdvanced::font_set_oversampling(const RID &p_font_rid, double p_oversampling) { +void TextServerAdvanced::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2244,7 +2259,7 @@ void TextServerAdvanced::font_set_oversampling(const RID &p_font_rid, double p_o } } -double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const { +double TextServerAdvanced::_font_get_oversampling(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2252,7 +2267,7 @@ double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const { return fd->oversampling; } -TypedArray<Vector2i> TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const { +TypedArray<Vector2i> TextServerAdvanced::_font_get_size_cache_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); @@ -2264,7 +2279,7 @@ TypedArray<Vector2i> TextServerAdvanced::font_get_size_cache_list(const RID &p_f return ret; } -void TextServerAdvanced::font_clear_size_cache(const RID &p_font_rid) { +void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2275,7 +2290,7 @@ void TextServerAdvanced::font_clear_size_cache(const RID &p_font_rid) { fd->cache.clear(); } -void TextServerAdvanced::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2286,7 +2301,7 @@ void TextServerAdvanced::font_remove_size_cache(const RID &p_font_rid, const Vec } } -void TextServerAdvanced::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { +void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2297,7 +2312,7 @@ void TextServerAdvanced::font_set_ascent(const RID &p_font_rid, int64_t p_size, fd->cache[size]->ascent = p_ascent; } -double TextServerAdvanced::font_get_ascent(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2313,7 +2328,7 @@ double TextServerAdvanced::font_get_ascent(const RID &p_font_rid, int64_t p_size } } -void TextServerAdvanced::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { +void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2323,7 +2338,7 @@ void TextServerAdvanced::font_set_descent(const RID &p_font_rid, int64_t p_size, fd->cache[size]->descent = p_descent; } -double TextServerAdvanced::font_get_descent(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2339,7 +2354,7 @@ double TextServerAdvanced::font_get_descent(const RID &p_font_rid, int64_t p_siz } } -void TextServerAdvanced::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { +void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2350,7 +2365,7 @@ void TextServerAdvanced::font_set_underline_position(const RID &p_font_rid, int6 fd->cache[size]->underline_position = p_underline_position; } -double TextServerAdvanced::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2366,7 +2381,7 @@ double TextServerAdvanced::font_get_underline_position(const RID &p_font_rid, in } } -void TextServerAdvanced::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { +void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2377,7 +2392,7 @@ void TextServerAdvanced::font_set_underline_thickness(const RID &p_font_rid, int fd->cache[size]->underline_thickness = p_underline_thickness; } -double TextServerAdvanced::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2393,7 +2408,7 @@ double TextServerAdvanced::font_get_underline_thickness(const RID &p_font_rid, i } } -void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { +void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2409,7 +2424,7 @@ void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, d fd->cache[size]->scale = p_scale; } -double TextServerAdvanced::font_get_scale(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2425,7 +2440,7 @@ double TextServerAdvanced::font_get_scale(const RID &p_font_rid, int64_t p_size) } } -int64_t TextServerAdvanced::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { +int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -2437,7 +2452,7 @@ int64_t TextServerAdvanced::font_get_texture_count(const RID &p_font_rid, const return fd->cache[size]->textures.size(); } -void TextServerAdvanced::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2447,7 +2462,7 @@ void TextServerAdvanced::font_clear_textures(const RID &p_font_rid, const Vector fd->cache[size]->textures.clear(); } -void TextServerAdvanced::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { +void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2459,7 +2474,7 @@ void TextServerAdvanced::font_remove_texture(const RID &p_font_rid, const Vector fd->cache[size]->textures.remove_at(p_texture_index); } -void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { +void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND(p_image.is_null()); @@ -2490,7 +2505,7 @@ void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vec 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 { +Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Ref<Image>()); @@ -2507,7 +2522,7 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, con return img; } -void TextServerAdvanced::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { +void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2523,7 +2538,7 @@ void TextServerAdvanced::font_set_texture_offsets(const RID &p_font_rid, const V tex.offsets = p_offset; } -PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { +PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -2536,7 +2551,7 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_ return tex.offsets; } -PackedInt32Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { +PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -2552,7 +2567,7 @@ PackedInt32Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, return ret; } -void TextServerAdvanced::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2563,7 +2578,7 @@ void TextServerAdvanced::font_clear_glyphs(const RID &p_font_rid, const Vector2i fd->cache[size]->glyph_map.clear(); } -void TextServerAdvanced::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { +void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2588,7 +2603,7 @@ double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) c } } -Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { +Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2599,7 +2614,7 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_ int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2625,7 +2640,7 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_ } } -void TextServerAdvanced::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { +void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2640,7 +2655,7 @@ void TextServerAdvanced::font_set_glyph_advance(const RID &p_font_rid, int64_t p gl[p_glyph].found = true; } -Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2651,7 +2666,7 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const V int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2670,7 +2685,7 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const V } } -void TextServerAdvanced::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { +void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2685,7 +2700,7 @@ void TextServerAdvanced::font_set_glyph_offset(const RID &p_font_rid, const Vect gl[p_glyph].found = true; } -Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2696,7 +2711,7 @@ Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vec int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2715,7 +2730,7 @@ Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vec } } -void TextServerAdvanced::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { +void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2730,7 +2745,7 @@ void TextServerAdvanced::font_set_glyph_size(const RID &p_font_rid, const Vector gl[p_glyph].found = true; } -Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Rect2()); @@ -2741,7 +2756,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2755,7 +2770,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve return gl[p_glyph | mod].uv_rect; } -void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { +void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2770,7 +2785,7 @@ void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vec gl[p_glyph].found = true; } -int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, -1); @@ -2781,7 +2796,7 @@ int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, co int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2795,7 +2810,7 @@ int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, co return gl[p_glyph | mod].texture_idx; } -void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { +void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2810,7 +2825,7 @@ void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const gl[p_glyph].found = true; } -RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, RID()); @@ -2821,7 +2836,7 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2858,7 +2873,7 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const return RID(); } -Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Size2()); @@ -2869,7 +2884,7 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -2906,7 +2921,7 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con return Size2(); } -Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { +Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2956,7 +2971,7 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in #endif } -TypedArray<Vector2i> TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { +TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); @@ -2972,7 +2987,7 @@ TypedArray<Vector2i> TextServerAdvanced::font_get_kerning_list(const RID &p_font return ret; } -void TextServerAdvanced::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { +void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2983,7 +2998,7 @@ void TextServerAdvanced::font_clear_kerning_map(const RID &p_font_rid, int64_t p fd->cache[size]->kerning_map.clear(); } -void TextServerAdvanced::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { +void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2994,7 +3009,7 @@ void TextServerAdvanced::font_remove_kerning(const RID &p_font_rid, int64_t p_si fd->cache[size]->kerning_map.erase(p_glyph_pair); } -void TextServerAdvanced::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { +void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3005,7 +3020,7 @@ void TextServerAdvanced::font_set_kerning(const RID &p_font_rid, int64_t p_size, fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; } -Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { +Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -3038,7 +3053,7 @@ Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_si return Vector2(); } -int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { +int64_t TextServerAdvanced::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); @@ -3063,7 +3078,7 @@ int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t #endif } -bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) const { +bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); if (!fd) { @@ -3084,7 +3099,7 @@ bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) co return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; } -String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const { +String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -3117,7 +3132,7 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const return chars; } -void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { +void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + "."); @@ -3152,7 +3167,7 @@ void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i } } -void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { +void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3183,7 +3198,7 @@ void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i #endif } -void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { +void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3198,7 +3213,7 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can if (!fd->msdf && fd->cache[size]->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -3275,7 +3290,7 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can } } -void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { +void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3290,7 +3305,7 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI if (!fd->msdf && fd->cache[size]->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -3367,7 +3382,7 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI } } -bool TextServerAdvanced::font_is_language_supported(const RID &p_font_rid, const String &p_language) const { +bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3379,7 +3394,7 @@ bool TextServerAdvanced::font_is_language_supported(const RID &p_font_rid, const } } -void TextServerAdvanced::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { +void TextServerAdvanced::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3387,7 +3402,7 @@ void TextServerAdvanced::font_set_language_support_override(const RID &p_font_ri fd->language_support_overrides[p_language] = p_supported; } -bool TextServerAdvanced::font_get_language_support_override(const RID &p_font_rid, const String &p_language) { +bool TextServerAdvanced::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3395,7 +3410,7 @@ bool TextServerAdvanced::font_get_language_support_override(const RID &p_font_ri return fd->language_support_overrides[p_language]; } -void TextServerAdvanced::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { +void TextServerAdvanced::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3403,7 +3418,7 @@ void TextServerAdvanced::font_remove_language_support_override(const RID &p_font fd->language_support_overrides.erase(p_language); } -PackedStringArray TextServerAdvanced::font_get_language_support_overrides(const RID &p_font_rid) { +PackedStringArray TextServerAdvanced::_font_get_language_support_overrides(const RID &p_font_rid) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedStringArray()); @@ -3415,7 +3430,7 @@ PackedStringArray TextServerAdvanced::font_get_language_support_overrides(const return out; } -bool TextServerAdvanced::font_is_script_supported(const RID &p_font_rid, const String &p_script) const { +bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3429,7 +3444,7 @@ bool TextServerAdvanced::font_is_script_supported(const RID &p_font_rid, const S } } -void TextServerAdvanced::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { +void TextServerAdvanced::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3437,7 +3452,7 @@ void TextServerAdvanced::font_set_script_support_override(const RID &p_font_rid, fd->script_support_overrides[p_script] = p_supported; } -bool TextServerAdvanced::font_get_script_support_override(const RID &p_font_rid, const String &p_script) { +bool TextServerAdvanced::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3445,7 +3460,7 @@ bool TextServerAdvanced::font_get_script_support_override(const RID &p_font_rid, return fd->script_support_overrides[p_script]; } -void TextServerAdvanced::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { +void TextServerAdvanced::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3453,7 +3468,7 @@ void TextServerAdvanced::font_remove_script_support_override(const RID &p_font_r fd->script_support_overrides.erase(p_script); } -PackedStringArray TextServerAdvanced::font_get_script_support_overrides(const RID &p_font_rid) { +PackedStringArray TextServerAdvanced::_font_get_script_support_overrides(const RID &p_font_rid) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedStringArray()); @@ -3465,7 +3480,7 @@ PackedStringArray TextServerAdvanced::font_get_script_support_overrides(const RI return out; } -void TextServerAdvanced::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { +void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3475,7 +3490,7 @@ void TextServerAdvanced::font_set_opentype_feature_overrides(const RID &p_font_r fd->feature_overrides = p_overrides; } -Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_get_opentype_feature_overrides(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3483,7 +3498,7 @@ Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(const RID &p_ return fd->feature_overrides; } -Dictionary TextServerAdvanced::font_supported_feature_list(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3493,7 +3508,7 @@ Dictionary TextServerAdvanced::font_supported_feature_list(const RID &p_font_rid return fd->supported_features; } -Dictionary TextServerAdvanced::font_supported_variation_list(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3503,11 +3518,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(const RID &p_font_r return fd->supported_varaitions; } -double TextServerAdvanced::font_get_global_oversampling() const { +double TextServerAdvanced::_font_get_global_oversampling() const { return oversampling; } -void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) { +void TextServerAdvanced::_font_set_global_oversampling(double p_oversampling) { _THREAD_SAFE_METHOD_ if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -3515,8 +3530,8 @@ void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) { font_owner.get_owned_list(&fonts); bool font_cleared = false; for (const RID &E : fonts) { - if (!font_is_multichannel_signed_distance_field(E) && font_get_oversampling(E) <= 0) { - font_clear_size_cache(E); + if (!_font_is_multichannel_signed_distance_field(E) && _font_get_oversampling(E) <= 0) { + _font_clear_size_cache(E); font_cleared = true; } } @@ -3625,7 +3640,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) { p_shaped->parent = RID(); } -RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { +RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced); @@ -3635,7 +3650,7 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te return shaped_owner.make_rid(sd); } -void TextServerAdvanced::shaped_text_clear(const RID &p_shaped) { +void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3650,7 +3665,7 @@ void TextServerAdvanced::shaped_text_clear(const RID &p_shaped) { invalidate(sd, true); } -void TextServerAdvanced::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { +void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3664,7 +3679,7 @@ void TextServerAdvanced::shaped_text_set_direction(const RID &p_shaped, TextServ } } -TextServer::Direction TextServerAdvanced::shaped_text_get_direction(const RID &p_shaped) const { +TextServer::Direction TextServerAdvanced::_shaped_text_get_direction(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); @@ -3672,7 +3687,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(const RID &p return sd->direction; } -TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(const RID &p_shaped) const { +TextServer::Direction TextServerAdvanced::_shaped_text_get_inferred_direction(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); @@ -3680,7 +3695,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(con return sd->para_direction; } -void TextServerAdvanced::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { +void TextServerAdvanced::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3694,14 +3709,14 @@ void TextServerAdvanced::shaped_text_set_custom_punctuation(const RID &p_shaped, } } -String TextServerAdvanced::shaped_text_get_custom_punctuation(const RID &p_shaped) const { +String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shaped) const { _THREAD_SAFE_METHOD_ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, String()); return sd->custom_punct; } -void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { +void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3718,7 +3733,7 @@ void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, cons invalidate(sd, false); } -void TextServerAdvanced::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { +void TextServerAdvanced::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3732,7 +3747,7 @@ void TextServerAdvanced::shaped_text_set_orientation(const RID &p_shaped, TextSe } } -void TextServerAdvanced::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { +void TextServerAdvanced::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3744,7 +3759,7 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(const RID &p_shaped, b } } -bool TextServerAdvanced::shaped_text_get_preserve_invalid(const RID &p_shaped) const { +bool TextServerAdvanced::_shaped_text_get_preserve_invalid(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3752,7 +3767,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_invalid(const RID &p_shaped) c return sd->preserve_invalid; } -void TextServerAdvanced::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { +void TextServerAdvanced::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3766,7 +3781,7 @@ void TextServerAdvanced::shaped_text_set_preserve_control(const RID &p_shaped, b } } -bool TextServerAdvanced::shaped_text_get_preserve_control(const RID &p_shaped) const { +bool TextServerAdvanced::_shaped_text_get_preserve_control(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3774,7 +3789,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_control(const RID &p_shaped) c return sd->preserve_control; } -void TextServerAdvanced::shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) { +void TextServerAdvanced::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) { ERR_FAIL_INDEX((int)p_spacing, 4); ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3789,7 +3804,7 @@ void TextServerAdvanced::shaped_text_set_spacing(const RID &p_shaped, SpacingTyp } } -int64_t TextServerAdvanced::shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const { +int64_t TextServerAdvanced::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const { ERR_FAIL_INDEX_V((int)p_spacing, 4, 0); const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); @@ -3799,7 +3814,7 @@ int64_t TextServerAdvanced::shaped_text_get_spacing(const RID &p_shaped, Spacing return sd->extra_spacing[p_spacing]; } -TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(const RID &p_shaped) const { +TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL); @@ -3807,41 +3822,33 @@ TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(const RI return sd->orientation; } -int64_t TextServerAdvanced::shaped_get_span_count(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); return sd->spans.size(); } -Variant TextServerAdvanced::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { +Variant TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Variant()); ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant()); return sd->spans[p_index].meta; } -void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { +void TextServerAdvanced::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); ERR_FAIL_INDEX(p_index, sd->spans.size()); ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index]; - bool changed = (span.font_size != p_size) || (span.features != p_opentype_features) || (p_fonts.size() != span.fonts.size()); - if (!changed) { - for (int i = 0; i < p_fonts.size(); i++) { - changed = changed || (span.fonts[i] != p_fonts[i]); - } - } - if (changed) { - span.fonts = p_fonts; - span.font_size = p_size; - span.features = p_opentype_features; + span.fonts = p_fonts; + span.font_size = p_size; + span.features = p_opentype_features; - invalidate(sd, false); - } + invalidate(sd, false); } -bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { +bool TextServerAdvanced::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); ERR_FAIL_COND_V(p_size <= 0, false); @@ -3876,7 +3883,7 @@ bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const Strin return true; } -bool TextServerAdvanced::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { +bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3906,7 +3913,7 @@ bool TextServerAdvanced::shaped_text_add_object(const RID &p_shaped, const Varia return true; } -bool TextServerAdvanced::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { +bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3947,14 +3954,14 @@ bool TextServerAdvanced::shaped_text_resize_object(const RID &p_shaped, const Va } else { if (gl.font_rid.is_valid()) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); - sd->descent = MAX(sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); + sd->ascent = MAX(sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); + sd->descent = MAX(sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); } else { - sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - sd->descent = MAX(sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size)); + sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { @@ -4041,7 +4048,7 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const { p_sd->descent = full_descent; } -RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { +RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { _THREAD_SAFE_METHOD_ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); @@ -4049,10 +4056,10 @@ RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, MutexLock lock(sd->mutex); if (sd->parent != RID()) { - return shaped_text_substr(sd->parent, p_start, p_length); + return _shaped_text_substr(sd->parent, p_start, p_length); } if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID()); ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID()); @@ -4156,11 +4163,11 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S } else { if (gl.font_rid.is_valid()) { if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) { - p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); - p_new_sd->descent = MAX(p_new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); + p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); + p_new_sd->descent = MAX(p_new_sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); } else { - p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - p_new_sd->descent = MAX(p_new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + p_new_sd->descent = MAX(p_new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } } else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. @@ -4186,7 +4193,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S return true; } -RID TextServerAdvanced::shaped_text_get_parent(const RID &p_shaped) const { +RID TextServerAdvanced::_shaped_text_get_parent(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); @@ -4194,16 +4201,16 @@ RID TextServerAdvanced::shaped_text_get_parent(const RID &p_shaped) const { return sd->parent; } -double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) { +double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->justification_ops_valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_update_justification_ops(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_update_justification_ops(p_shaped); } sd->fit_width_minimum_reached = false; @@ -4351,16 +4358,16 @@ double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double return Math::ceil(justification_width); } -double TextServerAdvanced::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { +double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_update_breaks(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_update_breaks(p_shaped); } for (int i = 0; i < p_tab_stops.size(); i++) { @@ -4407,13 +4414,13 @@ double TextServerAdvanced::shaped_text_tab_align(const RID &p_shaped, const Pack return 0.0; } -void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { +void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped_line); + _shaped_text_shape(p_shaped_line); } sd->text_trimmed = false; @@ -4452,30 +4459,30 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l // Find usable fonts, if fonts from the last glyph do not have required chars. RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!font_has_char(dot_gl_font_rid, '.')) { + if (!_font_has_char(dot_gl_font_rid, '.')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (font_has_char(fonts[i], '.')) { + if (_font_has_char(fonts[i], '.')) { dot_gl_font_rid = fonts[i]; break; } } } RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!font_has_char(whitespace_gl_font_rid, '.')) { + if (!_font_has_char(whitespace_gl_font_rid, '.')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (font_has_char(fonts[i], ' ')) { + if (_font_has_char(fonts[i], ' ')) { whitespace_gl_font_rid = fonts[i]; break; } } } - int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; - Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); - int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; - Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { @@ -4574,7 +4581,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l } } -int64_t TextServerAdvanced::shaped_text_get_trim_pos(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_trim_pos(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); @@ -4582,7 +4589,7 @@ int64_t TextServerAdvanced::shaped_text_get_trim_pos(const RID &p_shaped) const return sd->overrun_trim_data.trim_pos; } -int64_t TextServerAdvanced::shaped_text_get_ellipsis_pos(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); @@ -4590,7 +4597,7 @@ int64_t TextServerAdvanced::shaped_text_get_ellipsis_pos(const RID &p_shaped) co return sd->overrun_trim_data.ellipsis_pos; } -const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { +const Glyph *TextServerAdvanced::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid."); @@ -4598,7 +4605,7 @@ const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(const RID &p_sh return sd->overrun_trim_data.ellipsis_glyph_buf.ptr(); } -int64_t TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid."); @@ -4606,13 +4613,13 @@ int64_t TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(const RID &p_sh return sd->overrun_trim_data.ellipsis_glyph_buf.size(); } -bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { +bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped); + _shaped_text_shape(p_shaped); } if (sd->line_breaks_valid) { @@ -4823,16 +4830,16 @@ _FORCE_INLINE_ int64_t _generate_kashida_justification_opportunies(const String return kashida_pos; } -bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shaped) { +bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped); + _shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { - shaped_text_update_breaks(p_shaped); + _shaped_text_update_breaks(p_shaped); } if (sd->justification_ops_valid) { @@ -4977,7 +4984,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) { hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size); - bool subpos = (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); + bool subpos = (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); ERR_FAIL_COND_V(hb_font == nullptr, Glyph()); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -5003,7 +5010,7 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char gl.font_size = p_font_size; if (glyph_count > 0) { - double scale = font_get_scale(p_font, p_font_size); + double scale = _font_get_scale(p_font, p_font_size); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { if (subpos) { gl.advance = glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size); @@ -5038,7 +5045,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source if (value >= 0) { hb_feature_t feature; if (keys[i].get_type() == Variant::STRING) { - feature.tag = name_to_tag(keys[i]); + feature.tag = _name_to_tag(keys[i]); } else { feature.tag = keys[i]; } @@ -5089,12 +5096,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star 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 scale = _font_get_scale(f, fs); double sp_sp = p_sd->extra_spacing[SPACING_SPACE]; double sp_gl = p_sd->extra_spacing[SPACING_GLYPH]; bool last_run = (p_sd->end == p_end); double ea = _get_extra_advance(f, fs); - bool subpos = (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); + bool subpos = (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); ERR_FAIL_COND(hb_font == nullptr); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -5122,7 +5129,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start); Vector<hb_feature_t> ftrs; - _add_featuers(font_get_opentype_feature_overrides(f), ftrs); + _add_featuers(_font_get_opentype_feature_overrides(f), ftrs); _add_featuers(p_sd->spans[p_span].features, ftrs); hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size()); @@ -5133,7 +5140,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -5253,7 +5260,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off); p_sd->descent = MAX(p_sd->descent, w[i + j].y_off); } else { - double gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); + double gla = Math::round(_font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); p_sd->ascent = MAX(p_sd->ascent, gla); p_sd->descent = MAX(p_sd->descent, gla); } @@ -5276,14 +5283,14 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star if (failed_subrun_start != p_end + 1) { _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1); } - p_sd->ascent = MAX(p_sd->ascent, font_get_ascent(f, fs)); - p_sd->descent = MAX(p_sd->descent, font_get_descent(f, fs)); - p_sd->upos = MAX(p_sd->upos, font_get_underline_position(f, fs)); - p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(f, fs)); + p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs)); + p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs)); + p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs)); + p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs)); } } -bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { +bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -5294,7 +5301,7 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { invalidate(sd, false); if (sd->parent != RID()) { - shaped_text_shape(sd->parent); + _shaped_text_shape(sd->parent); ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); ERR_FAIL_COND_V(!parent_sd->valid, false); ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false); @@ -5430,9 +5437,12 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { Array fonts_scr_only; Array fonts_no_match; int font_count = span.fonts.size(); - for (int l = 0; l < font_count; l++) { - if (font_is_script_supported(span.fonts[l], script)) { - if (font_is_language_supported(span.fonts[l], span.language)) { + if (font_count > 0) { + fonts.push_back(sd->spans[k].fonts[0]); + } + for (int l = 1; l < font_count; l++) { + if (_font_is_script_supported(span.fonts[l], script)) { + if (_font_is_language_supported(span.fonts[l], span.language)) { fonts.push_back(sd->spans[k].fonts[l]); } else { fonts_scr_only.push_back(sd->spans[k].fonts[l]); @@ -5456,7 +5466,7 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { return sd->valid; } -bool TextServerAdvanced::shaped_text_is_ready(const RID &p_shaped) const { +bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -5464,35 +5474,35 @@ bool TextServerAdvanced::shaped_text_is_ready(const RID &p_shaped) const { return sd->valid; } -const Glyph *TextServerAdvanced::shaped_text_get_glyphs(const RID &p_shaped) const { +const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.ptr(); } -int64_t TextServerAdvanced::shaped_text_get_glyph_count(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.size(); } -const Glyph *TextServerAdvanced::shaped_text_sort_logical(const RID &p_shaped) { +const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->sort_valid) { @@ -5504,7 +5514,7 @@ const Glyph *TextServerAdvanced::shaped_text_sort_logical(const RID &p_shaped) { return sd->glyphs_logical.ptr(); } -Vector2i TextServerAdvanced::shaped_text_get_range(const RID &p_shaped) const { +Vector2i TextServerAdvanced::_shaped_text_get_range(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Vector2i()); @@ -5512,7 +5522,7 @@ Vector2i TextServerAdvanced::shaped_text_get_range(const RID &p_shaped) const { return Vector2(sd->start, sd->end); } -Array TextServerAdvanced::shaped_text_get_objects(const RID &p_shaped) const { +Array TextServerAdvanced::_shaped_text_get_objects(const RID &p_shaped) const { Array ret; const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, ret); @@ -5525,25 +5535,25 @@ Array TextServerAdvanced::shaped_text_get_objects(const RID &p_shaped) const { return ret; } -Rect2 TextServerAdvanced::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { +Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Rect2()); MutexLock lock(sd->mutex); ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2()); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->objects[p_key].rect; } -Size2 TextServerAdvanced::shaped_text_get_size(const RID &p_shaped) const { +Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Size2()); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil(); @@ -5552,58 +5562,58 @@ Size2 TextServerAdvanced::shaped_text_get_size(const RID &p_shaped) const { } } -double TextServerAdvanced::shaped_text_get_ascent(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->ascent + sd->extra_spacing[SPACING_TOP]; } -double TextServerAdvanced::shaped_text_get_descent(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->descent + sd->extra_spacing[SPACING_BOTTOM]; } -double TextServerAdvanced::shaped_text_get_width(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width); } -double TextServerAdvanced::shaped_text_get_underline_position(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->upos; } -double TextServerAdvanced::shaped_text_get_underline_thickness(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->uthk; @@ -5784,7 +5794,7 @@ void TextServerAdvanced::_insert_num_systems_lang() { } } -String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_format_number(const String &p_string, const String &p_language) const { const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; @@ -5809,7 +5819,7 @@ String TextServerAdvanced::format_number(const String &p_string, const String &p return res; } -String TextServerAdvanced::parse_number(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_parse_number(const String &p_string, const String &p_language) const { const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; @@ -5837,7 +5847,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_ return res; } -String TextServerAdvanced::percent_sign(const String &p_language) const { +String TextServerAdvanced::_percent_sign(const String &p_language) const { const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; for (int i = 0; i < num_systems.size(); i++) { @@ -5851,9 +5861,9 @@ String TextServerAdvanced::percent_sign(const String &p_language) const { return "%"; } -int TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const { +int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const { UErrorCode status = U_ZERO_ERROR; - int match_index = -1; + int64_t match_index = -1; Char16String utf16 = p_string.utf16(); Vector<UChar *> skeletons; @@ -5891,7 +5901,7 @@ int TextServerAdvanced::is_confusable(const String &p_string, const PackedString return match_index; } -bool TextServerAdvanced::spoof_check(const String &p_string) const { +bool TextServerAdvanced::_spoof_check(const String &p_string) const { UErrorCode status = U_ZERO_ERROR; Char16String utf16 = p_string.utf16(); @@ -5913,7 +5923,7 @@ bool TextServerAdvanced::spoof_check(const String &p_string) const { return (bitmask != 0); } -String TextServerAdvanced::strip_diacritics(const String &p_string) const { +String TextServerAdvanced::_strip_diacritics(const String &p_string) const { UErrorCode err = U_ZERO_ERROR; // Get NFKD normalizer singleton. @@ -5946,7 +5956,7 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const { return result; } -String TextServerAdvanced::string_to_upper(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. @@ -5965,7 +5975,7 @@ String TextServerAdvanced::string_to_upper(const String &p_string, const String return String::utf16(upper.ptr(), len); } -String TextServerAdvanced::string_to_lower(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. Char16String utf16 = p_string.utf16(); @@ -5983,7 +5993,7 @@ String TextServerAdvanced::string_to_lower(const String &p_string, const String return String::utf16(lower.ptr(), len); } -PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_string, const String &p_language) const { +PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. Char16String utf16 = p_string.utf16(); @@ -6031,7 +6041,7 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri return ret; } -bool TextServerAdvanced::is_valid_identifier(const String &p_string) const { +bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const { enum UAX31SequenceStatus { SEQ_NOT_STARTED, SEQ_STARTED, @@ -6052,7 +6062,7 @@ bool TextServerAdvanced::is_valid_identifier(const String &p_string) const { if (U_FAILURE(err)) { return false; // Failed to load normalizer. } - bool isnurom = unorm2_isNormalized(norm_c, utf16.ptr(), utf16.length(), &err); + bool isnurom = unorm2_isNormalized(norm_c, utf16.get_data(), utf16.length(), &err); if (U_FAILURE(err) || !isnurom) { return false; // Do not conform to Normalization Form C. } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 1db95d153b..fb5075e835 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -42,6 +42,7 @@ #include <godot_cpp/godot.hpp> #include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/ext_wrappers.gen.inc> #include <godot_cpp/core/mutex_lock.hpp> #include <godot_cpp/variant/array.hpp> @@ -52,6 +53,7 @@ #include <godot_cpp/variant/rect2.hpp> #include <godot_cpp/variant/rid.hpp> #include <godot_cpp/variant/string.hpp> +#include <godot_cpp/variant/typed_array.hpp> #include <godot_cpp/variant/vector2.hpp> #include <godot_cpp/variant/vector2i.hpp> @@ -78,11 +80,13 @@ using namespace godot; #else // Headers for building as built-in module. +#include "servers/text/text_server_extension.h" + +#include "core/extension/ext_wrappers.gen.inc" #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" #include "scene/resources/texture.h" -#include "servers/text/text_server_extension.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen. @@ -461,258 +465,259 @@ protected: void invalidate(ShapedTextDataAdvanced *p_shaped, bool p_text = false); public: - virtual bool has_feature(Feature p_feature) const override; - virtual String get_name() const override; - virtual int64_t get_features() const override; + MODBIND1RC(bool, has_feature, Feature); + MODBIND0RC(String, get_name); + MODBIND0RC(int64_t, get_features); - virtual void free_rid(const RID &p_rid) override; - virtual bool has(const RID &p_rid) override; - virtual bool load_support_data(const String &p_filename) override; + MODBIND1(free_rid, const RID &); + MODBIND1R(bool, has, const RID &); + MODBIND1R(bool, load_support_data, const String &); - virtual String get_support_data_filename() const override; - virtual String get_support_data_info() const override; - virtual bool save_support_data(const String &p_filename) const override; + MODBIND0RC(String, get_support_data_filename); + MODBIND0RC(String, get_support_data_info); + MODBIND1RC(bool, save_support_data, const String &); - virtual bool is_locale_right_to_left(const String &p_locale) const override; + MODBIND1RC(bool, is_locale_right_to_left, const String &); - virtual int64_t name_to_tag(const String &p_name) const override; - virtual String tag_to_name(int64_t p_tag) const override; + MODBIND1RC(int64_t, name_to_tag, const String &); + MODBIND1RC(String, tag_to_name, int64_t); /* Font interface */ - virtual RID create_font() override; - virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; - virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + MODBIND0R(RID, create_font); + + MODBIND2(font_set_data, const RID &, const PackedByteArray &); + MODBIND3(font_set_data_ptr, const RID &, const uint8_t *, int64_t); - virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override; - virtual int64_t font_get_face_index(const RID &p_font_rid) const override; + MODBIND2(font_set_face_index, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_face_index, const RID &); - virtual int64_t font_get_face_count(const RID &p_font_rid) const override; + MODBIND1RC(int64_t, font_get_face_count, const RID &); - virtual void font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) override; - virtual BitField<FontStyle> font_get_style(const RID &p_font_rid) const override; + MODBIND2(font_set_style, const RID &, BitField<FontStyle>); + MODBIND1RC(BitField<FontStyle>, font_get_style, const RID &); - virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override; - virtual String font_get_style_name(const RID &p_font_rid) const override; + MODBIND2(font_set_style_name, const RID &, const String &); + MODBIND1RC(String, font_get_style_name, const RID &); - virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; - virtual String font_get_name(const RID &p_font_rid) const override; + MODBIND2(font_set_name, const RID &, const String &); + MODBIND1RC(String, font_get_name, const RID &); - virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; - virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override; + MODBIND2(font_set_antialiasing, const RID &, TextServer::FontAntialiasing); + MODBIND1RC(TextServer::FontAntialiasing, font_get_antialiasing, const RID &); - virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; - virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; + MODBIND2(font_set_generate_mipmaps, const RID &, bool); + MODBIND1RC(bool, font_get_generate_mipmaps, const RID &); - virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override; - virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override; + MODBIND2(font_set_multichannel_signed_distance_field, const RID &, bool); + MODBIND1RC(bool, font_is_multichannel_signed_distance_field, const RID &); - virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override; - virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override; + MODBIND2(font_set_msdf_pixel_range, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_msdf_pixel_range, const RID &); - virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override; - virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override; + MODBIND2(font_set_msdf_size, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_msdf_size, const RID &); - virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override; - virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override; + MODBIND2(font_set_fixed_size, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_fixed_size, const RID &); - virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override; - virtual bool font_is_force_autohinter(const RID &p_font_rid) const override; + MODBIND2(font_set_force_autohinter, const RID &, bool); + MODBIND1RC(bool, font_is_force_autohinter, const RID &); - virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override; - virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override; + MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning); + MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &); - virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override; - virtual double font_get_embolden(const RID &p_font_rid) const override; + MODBIND2(font_set_embolden, const RID &, double); + MODBIND1RC(double, font_get_embolden, const RID &); - virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override; - virtual Transform2D font_get_transform(const RID &p_font_rid) const override; + MODBIND2(font_set_transform, const RID &, const Transform2D &); + MODBIND1RC(Transform2D, font_get_transform, const RID &); - virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override; - virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override; + MODBIND2(font_set_variation_coordinates, const RID &, const Dictionary &); + MODBIND1RC(Dictionary, font_get_variation_coordinates, const RID &); - virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override; - virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override; + MODBIND2(font_set_hinting, const RID &, TextServer::Hinting); + MODBIND1RC(TextServer::Hinting, font_get_hinting, const RID &); - virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; - virtual double font_get_oversampling(const RID &p_font_rid) const override; + MODBIND2(font_set_oversampling, const RID &, double); + MODBIND1RC(double, font_get_oversampling, const RID &); - virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override; - virtual void font_clear_size_cache(const RID &p_font_rid) override; - virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; + MODBIND1RC(TypedArray<Vector2i>, font_get_size_cache_list, const RID &); + MODBIND1(font_clear_size_cache, const RID &); + MODBIND2(font_remove_size_cache, const RID &, const Vector2i &); - virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override; - virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_ascent, const RID &, int64_t, double); + MODBIND2RC(double, font_get_ascent, const RID &, int64_t); - virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override; - virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_descent, const RID &, int64_t, double); + MODBIND2RC(double, font_get_descent, const RID &, int64_t); - virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override; - virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_underline_position, const RID &, int64_t, double); + MODBIND2RC(double, font_get_underline_position, const RID &, int64_t); - virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override; - virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_underline_thickness, const RID &, int64_t, double); + MODBIND2RC(double, font_get_underline_thickness, const RID &, int64_t); - virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override; - virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_scale, const RID &, int64_t, double); + MODBIND2RC(double, font_get_scale, const RID &, int64_t); - virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override; + MODBIND2RC(int64_t, font_get_texture_count, const RID &, const Vector2i &); + MODBIND2(font_clear_textures, const RID &, const Vector2i &); + MODBIND3(font_remove_texture, const RID &, const Vector2i &, int64_t); - virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override; - virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; + MODBIND4(font_set_texture_image, const RID &, const Vector2i &, int64_t, const Ref<Image> &); + MODBIND3RC(Ref<Image>, font_get_texture_image, const RID &, const Vector2i &, int64_t); - virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; - virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; + MODBIND4(font_set_texture_offsets, const RID &, const Vector2i &, int64_t, const PackedInt32Array &); + MODBIND3RC(PackedInt32Array, font_get_texture_offsets, const RID &, const Vector2i &, int64_t); - virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; + MODBIND2RC(PackedInt32Array, font_get_glyph_list, const RID &, const Vector2i &); + MODBIND2(font_clear_glyphs, const RID &, const Vector2i &); + MODBIND3(font_remove_glyph, const RID &, const Vector2i &, int64_t); - virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override; + MODBIND3RC(Vector2, font_get_glyph_advance, const RID &, int64_t, int64_t); + MODBIND4(font_set_glyph_advance, const RID &, int64_t, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override; + MODBIND3RC(Vector2, font_get_glyph_offset, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_offset, const RID &, const Vector2i &, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override; + MODBIND3RC(Vector2, font_get_glyph_size, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_size, const RID &, const Vector2i &, int64_t, const Vector2 &); - virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override; + MODBIND3RC(Rect2, font_get_glyph_uv_rect, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_uv_rect, const RID &, const Vector2i &, int64_t, const Rect2 &); - virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override; + MODBIND3RC(int64_t, font_get_glyph_texture_idx, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_texture_idx, const RID &, const Vector2i &, int64_t, int64_t); - virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + MODBIND3RC(RID, font_get_glyph_texture_rid, const RID &, const Vector2i &, int64_t); + MODBIND3RC(Size2, font_get_glyph_texture_size, const RID &, const Vector2i &, int64_t); - virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; + MODBIND3RC(Dictionary, font_get_glyph_contours, const RID &, int64_t, int64_t); - virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; - virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; + MODBIND2RC(TypedArray<Vector2i>, font_get_kerning_list, const RID &, int64_t); + MODBIND2(font_clear_kerning_map, const RID &, int64_t); + MODBIND3(font_remove_kerning, const RID &, int64_t, const Vector2i &); - virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; - virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override; + MODBIND4(font_set_kerning, const RID &, int64_t, const Vector2i &, const Vector2 &); + MODBIND3RC(Vector2, font_get_kerning, const RID &, int64_t, const Vector2i &); - virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override; + MODBIND4RC(int64_t, font_get_glyph_index, const RID &, int64_t, int64_t, int64_t); - virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override; - virtual String font_get_supported_chars(const RID &p_font_rid) const override; + MODBIND2RC(bool, font_has_char, const RID &, int64_t); + MODBIND1RC(String, font_get_supported_chars, const RID &); - virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override; - virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override; + MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t); + MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t); - virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + MODBIND6C(font_draw_glyph, const RID &, const RID &, int64_t, const Vector2 &, int64_t, const Color &); + MODBIND7C(font_draw_glyph_outline, const RID &, const RID &, int64_t, int64_t, const Vector2 &, int64_t, const Color &); - virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override; - virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override; - virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override; - virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override; - virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override; + MODBIND2RC(bool, font_is_language_supported, const RID &, const String &); + MODBIND3(font_set_language_support_override, const RID &, const String &, bool); + MODBIND2R(bool, font_get_language_support_override, const RID &, const String &); + MODBIND2(font_remove_language_support_override, const RID &, const String &); + MODBIND1R(PackedStringArray, font_get_language_support_overrides, const RID &); - virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override; - virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override; - virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override; - virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override; - virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override; + MODBIND2RC(bool, font_is_script_supported, const RID &, const String &); + MODBIND3(font_set_script_support_override, const RID &, const String &, bool); + MODBIND2R(bool, font_get_script_support_override, const RID &, const String &); + MODBIND2(font_remove_script_support_override, const RID &, const String &); + MODBIND1R(PackedStringArray, font_get_script_support_overrides, const RID &); - virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override; - virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override; + MODBIND2(font_set_opentype_feature_overrides, const RID &, const Dictionary &); + MODBIND1RC(Dictionary, font_get_opentype_feature_overrides, const RID &); - virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override; - virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override; + MODBIND1RC(Dictionary, font_supported_feature_list, const RID &); + MODBIND1RC(Dictionary, font_supported_variation_list, const RID &); - virtual double font_get_global_oversampling() const override; - virtual void font_set_global_oversampling(double p_oversampling) override; + MODBIND0RC(double, font_get_global_oversampling); + MODBIND1(font_set_global_oversampling, double); /* Shaped text buffer interface */ - virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + MODBIND2R(RID, create_shaped_text, Direction, Orientation); - virtual void shaped_text_clear(const RID &p_shaped) override; + MODBIND1(shaped_text_clear, const RID &); - virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override; - virtual Direction shaped_text_get_direction(const RID &p_shaped) const override; - virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_direction, const RID &, Direction); + MODBIND1RC(Direction, shaped_text_get_direction, const RID &); + MODBIND1RC(Direction, shaped_text_get_inferred_direction, const RID &); - virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override; + MODBIND2(shaped_text_set_bidi_override, const RID &, const Array &); - virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override; - virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_custom_punctuation, const RID &, const String &); + MODBIND1RC(String, shaped_text_get_custom_punctuation, const RID &); - virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_orientation, const RID &, Orientation); + MODBIND1RC(Orientation, shaped_text_get_orientation, const RID &); - virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_preserve_invalid, const RID &, bool); + MODBIND1RC(bool, shaped_text_get_preserve_invalid, const RID &); - virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_preserve_control, const RID &, bool); + MODBIND1RC(bool, shaped_text_get_preserve_control, const RID &); - virtual void shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) override; - virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const override; + MODBIND3(shaped_text_set_spacing, const RID &, SpacingType, int64_t); + MODBIND2RC(int64_t, shaped_text_get_spacing, const RID &, SpacingType); - virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; - virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override; - virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; + MODBIND7R(bool, shaped_text_add_string, const RID &, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &); + MODBIND5R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t); + MODBIND4R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment); - virtual int64_t shaped_get_span_count(const RID &p_shaped) const override; - virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override; - virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override; + MODBIND1RC(int64_t, shaped_get_span_count, const RID &); + MODBIND2RC(Variant, shaped_get_span_meta, const RID &, int64_t); + MODBIND5(shaped_set_span_update_font, const RID &, int64_t, const TypedArray<RID> &, int64_t, const Dictionary &); - virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override; - virtual RID shaped_text_get_parent(const RID &p_shaped) const override; + MODBIND3RC(RID, shaped_text_substr, const RID &, int64_t, int64_t); + MODBIND1RC(RID, shaped_text_get_parent, const RID &); - virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; - virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override; + MODBIND3R(double, shaped_text_fit_to_width, const RID &, double, BitField<TextServer::JustificationFlag>); + MODBIND2R(double, shaped_text_tab_align, const RID &, const PackedFloat32Array &); - virtual bool shaped_text_shape(const RID &p_shaped) override; - virtual bool shaped_text_update_breaks(const RID &p_shaped) override; - virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override; + MODBIND1R(bool, shaped_text_shape, const RID &); + MODBIND1R(bool, shaped_text_update_breaks, const RID &); + MODBIND1R(bool, shaped_text_update_justification_ops, const RID &); - virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override; - virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override; - virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override; + MODBIND1RC(int64_t, shaped_text_get_trim_pos, const RID &); + MODBIND1RC(int64_t, shaped_text_get_ellipsis_pos, const RID &); + MODBIND1RC(const Glyph *, shaped_text_get_ellipsis_glyphs, const RID &); + MODBIND1RC(int64_t, shaped_text_get_ellipsis_glyph_count, const RID &); - virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) override; + MODBIND3(shaped_text_overrun_trim_to_width, const RID &, double, BitField<TextServer::TextOverrunFlag>); - virtual bool shaped_text_is_ready(const RID &p_shaped) const override; + MODBIND1RC(bool, shaped_text_is_ready, const RID &); - virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override; - virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override; + MODBIND1RC(const Glyph *, shaped_text_get_glyphs, const RID &); + MODBIND1R(const Glyph *, shaped_text_sort_logical, const RID &); + MODBIND1RC(int64_t, shaped_text_get_glyph_count, const RID &); - virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override; + MODBIND1RC(Vector2i, shaped_text_get_range, const RID &); - virtual Array shaped_text_get_objects(const RID &p_shaped) const override; - virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override; + MODBIND1RC(Array, shaped_text_get_objects, const RID &); + MODBIND2RC(Rect2, shaped_text_get_object_rect, const RID &, const Variant &); - virtual Size2 shaped_text_get_size(const RID &p_shaped) const override; - virtual double shaped_text_get_ascent(const RID &p_shaped) const override; - virtual double shaped_text_get_descent(const RID &p_shaped) const override; - virtual double shaped_text_get_width(const RID &p_shaped) const override; - virtual double shaped_text_get_underline_position(const RID &p_shaped) const override; - virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override; + MODBIND1RC(Size2, shaped_text_get_size, const RID &); + MODBIND1RC(double, shaped_text_get_ascent, const RID &); + MODBIND1RC(double, shaped_text_get_descent, const RID &); + MODBIND1RC(double, shaped_text_get_width, const RID &); + MODBIND1RC(double, shaped_text_get_underline_position, const RID &); + MODBIND1RC(double, shaped_text_get_underline_thickness, const RID &); - virtual String format_number(const String &p_string, const String &p_language = "") const override; - virtual String parse_number(const String &p_string, const String &p_language = "") const override; - virtual String percent_sign(const String &p_language = "") const override; + MODBIND2RC(String, format_number, const String &, const String &); + MODBIND2RC(String, parse_number, const String &, const String &); + MODBIND1RC(String, percent_sign, const String &); - virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override; + MODBIND2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &); - virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override; - virtual bool spoof_check(const String &p_string) const override; + MODBIND2RC(int64_t, is_confusable, const String &, const PackedStringArray &); + MODBIND1RC(bool, spoof_check, const String &); - virtual String strip_diacritics(const String &p_string) const override; - virtual bool is_valid_identifier(const String &p_string) const override; + MODBIND1RC(String, strip_diacritics, const String &); + MODBIND1RC(bool, is_valid_identifier, const String &); - virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; - virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + MODBIND2RC(String, string_to_upper, const String &, const String &); + MODBIND2RC(String, string_to_lower, const String &, const String &); TextServerAdvanced(); ~TextServerAdvanced(); diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index de0a549900..eae8e031bf 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -19,6 +19,7 @@ env = SConscript("./godot-cpp/SConstruct") env.__class__.disable_warnings = methods.disable_warnings opts = Variables([], ARGUMENTS) +opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True)) opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True)) opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True)) opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False)) @@ -157,6 +158,25 @@ if env["freetype_enabled"]: ] thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources] + if env["brotli_enabled"]: + thirdparty_brotli_dir = "../../../thirdparty/brotli/" + thirdparty_brotli_sources = [ + "common/constants.c", + "common/context.c", + "common/dictionary.c", + "common/platform.c", + "common/shared_dictionary.c", + "common/transform.c", + "dec/bit_reader.c", + "dec/decode.c", + "dec/huffman.c", + "dec/state.c", + ] + thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] + env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) + env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir]) env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"]) @@ -168,7 +188,7 @@ if env["freetype_enabled"]: "FT_CONFIG_OPTION_SYSTEM_ZLIB", ] ) - if env["target"] == "debug": + if env.dev_build: env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 7bed22fbb1..518c877baa 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -33,7 +33,7 @@ #ifdef GDEXTENSION // Headers for building as GDExtension plug-in. -#include <godot_cpp/classes/file.hpp> +#include <godot_cpp/classes/file_access.hpp> #include <godot_cpp/classes/project_settings.hpp> #include <godot_cpp/classes/rendering_server.hpp> #include <godot_cpp/classes/translation_server.hpp> @@ -66,7 +66,7 @@ using namespace godot; #define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xff) << 24) | (((uint32_t)(c2)&0xff) << 16) | (((uint32_t)(c3)&0xff) << 8) | ((uint32_t)(c4)&0xff))) -bool TextServerFallback::has_feature(Feature p_feature) const { +bool TextServerFallback::_has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_SIMPLE_LAYOUT: case FEATURE_FONT_BITMAP: @@ -83,7 +83,7 @@ bool TextServerFallback::has_feature(Feature p_feature) const { return false; } -String TextServerFallback::get_name() const { +String TextServerFallback::_get_name() const { #ifdef GDEXTENSION return "Fallback (GDExtension)"; #else @@ -91,7 +91,7 @@ String TextServerFallback::get_name() const { #endif } -int64_t TextServerFallback::get_features() const { +int64_t TextServerFallback::_get_features() const { int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP; #ifdef MODULE_FREETYPE_ENABLED interface_features |= FEATURE_FONT_DYNAMIC; @@ -103,7 +103,7 @@ int64_t TextServerFallback::get_features() const { return interface_features; } -void TextServerFallback::free_rid(const RID &p_rid) { +void TextServerFallback::_free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontFallback *fd = font_owner.get_or_null(p_rid); @@ -116,20 +116,28 @@ void TextServerFallback::free_rid(const RID &p_rid) { } } -bool TextServerFallback::has(const RID &p_rid) { +bool TextServerFallback::_has(const RID &p_rid) { _THREAD_SAFE_METHOD_ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid); } -bool TextServerFallback::load_support_data(const String &p_filename) { +String TextServerFallback::_get_support_data_filename() const { + return ""; +}; + +String TextServerFallback::_get_support_data_info() const { + return "Not supported"; +}; + +bool TextServerFallback::_load_support_data(const String &p_filename) { return false; // No extra data used. } -bool TextServerFallback::save_support_data(const String &p_filename) const { +bool TextServerFallback::_save_support_data(const String &p_filename) const { return false; // No extra data used. } -bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const { +bool TextServerFallback::_is_locale_right_to_left(const String &p_locale) const { return false; // No RTL support. } @@ -169,7 +177,7 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) { return OT_TAG(tag[0], tag[1], tag[2], tag[3]); } -int64_t TextServerFallback::name_to_tag(const String &p_name) const { +int64_t TextServerFallback::_name_to_tag(const String &p_name) const { if (feature_sets.has(p_name)) { return feature_sets[p_name]; } @@ -185,7 +193,7 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) { p_buf[3] = (char)(uint8_t)(p_tag >> 0); } -String TextServerFallback::tag_to_name(int64_t p_tag) const { +String TextServerFallback::_tag_to_name(int64_t p_tag) const { if (feature_sets_inv.has(p_tag)) { return feature_sets_inv[p_tag]; } @@ -467,8 +475,14 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( td.projection = &projection; td.distancePixelConversion = &distancePixelConversion; +#ifdef GDEXTENSION + for (int i = 0; i < h; i++) { + _generateMTSDF_threaded(i, &td); + } +#else WorkerThreadPool::GroupID group_id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, SNAME("TextServerFBRenderMSDF")); WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_id); +#endif msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); @@ -840,7 +854,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f fd->oversampling = 1.0; fd->size.x = p_font_data->msdf_source_size; } else if (p_font_data->oversampling <= 0.0) { - fd->oversampling = font_get_global_oversampling(); + fd->oversampling = _font_get_global_oversampling(); } else { fd->oversampling = p_font_data->oversampling; } @@ -921,8 +935,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } - if (p_font_data->variation_coordinates.has(tag_to_name(var_tag))) { - var_value = p_font_data->variation_coordinates[tag_to_name(var_tag)]; + if (p_font_data->variation_coordinates.has(_tag_to_name(var_tag))) { + var_value = p_font_data->variation_coordinates[_tag_to_name(var_tag)]; coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } } @@ -948,7 +962,7 @@ _FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontFallback *p_font_d p_font_data->supported_varaitions.clear(); } -RID TextServerFallback::create_font() { +RID TextServerFallback::_create_font() { _THREAD_SAFE_METHOD_ FontFallback *fd = memnew(FontFallback); @@ -956,7 +970,7 @@ RID TextServerFallback::create_font() { return font_owner.make_rid(fd); } -void TextServerFallback::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { +void TextServerFallback::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -967,7 +981,7 @@ void TextServerFallback::font_set_data(const RID &p_font_rid, const PackedByteAr fd->data_size = fd->data.size(); } -void TextServerFallback::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { +void TextServerFallback::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -978,7 +992,7 @@ void TextServerFallback::font_set_data_ptr(const RID &p_font_rid, const uint8_t fd->data_size = p_data_size; } -void TextServerFallback::font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) { +void TextServerFallback::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -988,7 +1002,7 @@ void TextServerFallback::font_set_style(const RID &p_font_rid, BitField<FontStyl fd->style_flags = p_style; } -void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { +void TextServerFallback::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { ERR_FAIL_COND(p_face_index < 0); ERR_FAIL_COND(p_face_index >= 0x7FFF); @@ -1002,7 +1016,7 @@ void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_fa } } -int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const { +int64_t TextServerFallback::_font_get_face_index(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1010,7 +1024,7 @@ int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const { return fd->face_index; } -int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const { +int64_t TextServerFallback::_font_get_face_count(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1051,7 +1065,7 @@ int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const { return face_count; } -BitField<TextServer::FontStyle> TextServerFallback::font_get_style(const RID &p_font_rid) const { +BitField<TextServer::FontStyle> TextServerFallback::_font_get_style(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1061,7 +1075,7 @@ BitField<TextServer::FontStyle> TextServerFallback::font_get_style(const RID &p_ return fd->style_flags; } -void TextServerFallback::font_set_style_name(const RID &p_font_rid, const String &p_name) { +void TextServerFallback::_font_set_style_name(const RID &p_font_rid, const String &p_name) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1071,7 +1085,7 @@ void TextServerFallback::font_set_style_name(const RID &p_font_rid, const String fd->style_name = p_name; } -String TextServerFallback::font_get_style_name(const RID &p_font_rid) const { +String TextServerFallback::_font_get_style_name(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1081,7 +1095,7 @@ String TextServerFallback::font_get_style_name(const RID &p_font_rid) const { return fd->style_name; } -void TextServerFallback::font_set_name(const RID &p_font_rid, const String &p_name) { +void TextServerFallback::_font_set_name(const RID &p_font_rid, const String &p_name) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1091,7 +1105,7 @@ void TextServerFallback::font_set_name(const RID &p_font_rid, const String &p_na fd->font_name = p_name; } -String TextServerFallback::font_get_name(const RID &p_font_rid) const { +String TextServerFallback::_font_get_name(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1101,7 +1115,7 @@ String TextServerFallback::font_get_name(const RID &p_font_rid) const { return fd->font_name; } -void TextServerFallback::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) { +void TextServerFallback::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1112,7 +1126,7 @@ void TextServerFallback::font_set_antialiasing(RID p_font_rid, TextServer::FontA } } -TextServer::FontAntialiasing TextServerFallback::font_get_antialiasing(RID p_font_rid) const { +TextServer::FontAntialiasing TextServerFallback::_font_get_antialiasing(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE); @@ -1120,7 +1134,7 @@ TextServer::FontAntialiasing TextServerFallback::font_get_antialiasing(RID p_fon return fd->antialiasing; } -void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { +void TextServerFallback::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1129,13 +1143,14 @@ void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p for (KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) { for (int i = 0; i < E.value->textures.size(); i++) { E.value->textures.write[i].dirty = true; + E.value->textures.write[i].texture = Ref<ImageTexture>(); } } fd->mipmaps = p_generate_mipmaps; } } -bool TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const { +bool TextServerFallback::_font_get_generate_mipmaps(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1143,7 +1158,7 @@ bool TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const return fd->mipmaps; } -void TextServerFallback::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { +void TextServerFallback::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1154,7 +1169,7 @@ void TextServerFallback::font_set_multichannel_signed_distance_field(const RID & } } -bool TextServerFallback::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { +bool TextServerFallback::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1162,7 +1177,7 @@ bool TextServerFallback::font_is_multichannel_signed_distance_field(const RID &p return fd->msdf; } -void TextServerFallback::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { +void TextServerFallback::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1173,7 +1188,7 @@ void TextServerFallback::font_set_msdf_pixel_range(const RID &p_font_rid, int64_ } } -int64_t TextServerFallback::font_get_msdf_pixel_range(const RID &p_font_rid) const { +int64_t TextServerFallback::_font_get_msdf_pixel_range(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1181,7 +1196,7 @@ int64_t TextServerFallback::font_get_msdf_pixel_range(const RID &p_font_rid) con return fd->msdf_range; } -void TextServerFallback::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { +void TextServerFallback::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1192,7 +1207,7 @@ void TextServerFallback::font_set_msdf_size(const RID &p_font_rid, int64_t p_msd } } -int64_t TextServerFallback::font_get_msdf_size(const RID &p_font_rid) const { +int64_t TextServerFallback::_font_get_msdf_size(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1200,7 +1215,7 @@ int64_t TextServerFallback::font_get_msdf_size(const RID &p_font_rid) const { return fd->msdf_source_size; } -void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { +void TextServerFallback::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1208,7 +1223,7 @@ void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi fd->fixed_size = p_fixed_size; } -int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const { +int64_t TextServerFallback::_font_get_fixed_size(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1216,7 +1231,7 @@ int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const { return fd->fixed_size; } -void TextServerFallback::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { +void TextServerFallback::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1227,7 +1242,7 @@ void TextServerFallback::font_set_force_autohinter(const RID &p_font_rid, bool p } } -bool TextServerFallback::font_is_force_autohinter(const RID &p_font_rid) const { +bool TextServerFallback::_font_is_force_autohinter(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -1235,7 +1250,7 @@ bool TextServerFallback::font_is_force_autohinter(const RID &p_font_rid) const { return fd->force_autohinter; } -void TextServerFallback::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { +void TextServerFallback::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1246,7 +1261,7 @@ void TextServerFallback::font_set_hinting(const RID &p_font_rid, TextServer::Hin } } -TextServer::Hinting TextServerFallback::font_get_hinting(const RID &p_font_rid) const { +TextServer::Hinting TextServerFallback::_font_get_hinting(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, HINTING_NONE); @@ -1254,7 +1269,7 @@ TextServer::Hinting TextServerFallback::font_get_hinting(const RID &p_font_rid) return fd->hinting; } -void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { +void TextServerFallback::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1262,7 +1277,7 @@ void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, Te fd->subpixel_positioning = p_subpixel; } -TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(const RID &p_font_rid) const { +TextServer::SubpixelPositioning TextServerFallback::_font_get_subpixel_positioning(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED); @@ -1270,7 +1285,7 @@ TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positionin return fd->subpixel_positioning; } -void TextServerFallback::font_set_embolden(const RID &p_font_rid, double p_strength) { +void TextServerFallback::_font_set_embolden(const RID &p_font_rid, double p_strength) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1281,7 +1296,7 @@ void TextServerFallback::font_set_embolden(const RID &p_font_rid, double p_stren } } -double TextServerFallback::font_get_embolden(const RID &p_font_rid) const { +double TextServerFallback::_font_get_embolden(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1289,7 +1304,7 @@ double TextServerFallback::font_get_embolden(const RID &p_font_rid) const { return fd->embolden; } -void TextServerFallback::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { +void TextServerFallback::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1300,7 +1315,7 @@ void TextServerFallback::font_set_transform(const RID &p_font_rid, const Transfo } } -Transform2D TextServerFallback::font_get_transform(const RID &p_font_rid) const { +Transform2D TextServerFallback::_font_get_transform(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Transform2D()); @@ -1308,7 +1323,7 @@ Transform2D TextServerFallback::font_get_transform(const RID &p_font_rid) const return fd->transform; } -void TextServerFallback::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { +void TextServerFallback::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1319,7 +1334,7 @@ void TextServerFallback::font_set_variation_coordinates(const RID &p_font_rid, c } } -Dictionary TextServerFallback::font_get_variation_coordinates(const RID &p_font_rid) const { +Dictionary TextServerFallback::_font_get_variation_coordinates(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -1327,7 +1342,7 @@ Dictionary TextServerFallback::font_get_variation_coordinates(const RID &p_font_ return fd->variation_coordinates; } -void TextServerFallback::font_set_oversampling(const RID &p_font_rid, double p_oversampling) { +void TextServerFallback::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1338,7 +1353,7 @@ void TextServerFallback::font_set_oversampling(const RID &p_font_rid, double p_o } } -double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const { +double TextServerFallback::_font_get_oversampling(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1346,7 +1361,7 @@ double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const { return fd->oversampling; } -TypedArray<Vector2i> TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const { +TypedArray<Vector2i> TextServerFallback::_font_get_size_cache_list(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); @@ -1358,7 +1373,7 @@ TypedArray<Vector2i> TextServerFallback::font_get_size_cache_list(const RID &p_f return ret; } -void TextServerFallback::font_clear_size_cache(const RID &p_font_rid) { +void TextServerFallback::_font_clear_size_cache(const RID &p_font_rid) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1369,7 +1384,7 @@ void TextServerFallback::font_clear_size_cache(const RID &p_font_rid) { fd->cache.clear(); } -void TextServerFallback::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerFallback::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1380,7 +1395,7 @@ void TextServerFallback::font_remove_size_cache(const RID &p_font_rid, const Vec } } -void TextServerFallback::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { +void TextServerFallback::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1391,7 +1406,7 @@ void TextServerFallback::font_set_ascent(const RID &p_font_rid, int64_t p_size, fd->cache[size]->ascent = p_ascent; } -double TextServerFallback::font_get_ascent(const RID &p_font_rid, int64_t p_size) const { +double TextServerFallback::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1407,7 +1422,7 @@ double TextServerFallback::font_get_ascent(const RID &p_font_rid, int64_t p_size } } -void TextServerFallback::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { +void TextServerFallback::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1417,7 +1432,7 @@ void TextServerFallback::font_set_descent(const RID &p_font_rid, int64_t p_size, fd->cache[size]->descent = p_descent; } -double TextServerFallback::font_get_descent(const RID &p_font_rid, int64_t p_size) const { +double TextServerFallback::_font_get_descent(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1433,7 +1448,7 @@ double TextServerFallback::font_get_descent(const RID &p_font_rid, int64_t p_siz } } -void TextServerFallback::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { +void TextServerFallback::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1444,7 +1459,7 @@ void TextServerFallback::font_set_underline_position(const RID &p_font_rid, int6 fd->cache[size]->underline_position = p_underline_position; } -double TextServerFallback::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { +double TextServerFallback::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1460,7 +1475,7 @@ double TextServerFallback::font_get_underline_position(const RID &p_font_rid, in } } -void TextServerFallback::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { +void TextServerFallback::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1471,7 +1486,7 @@ void TextServerFallback::font_set_underline_thickness(const RID &p_font_rid, int fd->cache[size]->underline_thickness = p_underline_thickness; } -double TextServerFallback::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { +double TextServerFallback::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1487,7 +1502,7 @@ double TextServerFallback::font_get_underline_thickness(const RID &p_font_rid, i } } -void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { +void TextServerFallback::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1503,7 +1518,7 @@ void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, d fd->cache[size]->scale = p_scale; } -double TextServerFallback::font_get_scale(const RID &p_font_rid, int64_t p_size) const { +double TextServerFallback::_font_get_scale(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -1519,7 +1534,7 @@ double TextServerFallback::font_get_scale(const RID &p_font_rid, int64_t p_size) } } -int64_t TextServerFallback::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { +int64_t TextServerFallback::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1531,7 +1546,7 @@ int64_t TextServerFallback::font_get_texture_count(const RID &p_font_rid, const return fd->cache[size]->textures.size(); } -void TextServerFallback::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerFallback::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1541,7 +1556,7 @@ void TextServerFallback::font_clear_textures(const RID &p_font_rid, const Vector fd->cache[size]->textures.clear(); } -void TextServerFallback::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { +void TextServerFallback::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1553,7 +1568,7 @@ void TextServerFallback::font_remove_texture(const RID &p_font_rid, const Vector fd->cache[size]->textures.remove_at(p_texture_index); } -void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { +void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND(p_image.is_null()); @@ -1584,7 +1599,7 @@ void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vec 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 { +Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Ref<Image>()); @@ -1601,7 +1616,7 @@ Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, con return img; } -void TextServerFallback::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { +void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1617,7 +1632,7 @@ void TextServerFallback::font_set_texture_offsets(const RID &p_font_rid, const V tex.offsets = p_offset; } -PackedInt32Array TextServerFallback::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { +PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -1630,7 +1645,7 @@ PackedInt32Array TextServerFallback::font_get_texture_offsets(const RID &p_font_ return tex.offsets; } -PackedInt32Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { +PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -1646,7 +1661,7 @@ PackedInt32Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, return ret; } -void TextServerFallback::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerFallback::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1657,7 +1672,7 @@ void TextServerFallback::font_clear_glyphs(const RID &p_font_rid, const Vector2i fd->cache[size]->glyph_map.clear(); } -void TextServerFallback::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { +void TextServerFallback::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1668,7 +1683,7 @@ void TextServerFallback::font_remove_glyph(const RID &p_font_rid, const Vector2i fd->cache[size]->glyph_map.erase(p_glyph); } -Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { +Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1679,7 +1694,7 @@ Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_ int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1705,7 +1720,7 @@ Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_ } } -void TextServerFallback::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { +void TextServerFallback::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1720,7 +1735,7 @@ void TextServerFallback::font_set_glyph_advance(const RID &p_font_rid, int64_t p gl[p_glyph].found = true; } -Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1731,7 +1746,7 @@ Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const V int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1750,7 +1765,7 @@ Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const V } } -void TextServerFallback::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { +void TextServerFallback::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1765,7 +1780,7 @@ void TextServerFallback::font_set_glyph_offset(const RID &p_font_rid, const Vect gl[p_glyph].found = true; } -Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -1776,7 +1791,7 @@ Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vec int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1795,7 +1810,7 @@ Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vec } } -void TextServerFallback::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { +void TextServerFallback::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1810,7 +1825,7 @@ void TextServerFallback::font_set_glyph_size(const RID &p_font_rid, const Vector gl[p_glyph].found = true; } -Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Rect2()); @@ -1821,7 +1836,7 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1835,7 +1850,7 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve return gl[p_glyph | mod].uv_rect; } -void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { +void TextServerFallback::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1850,7 +1865,7 @@ void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vec gl[p_glyph].found = true; } -int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, -1); @@ -1861,7 +1876,7 @@ int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, co int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1875,7 +1890,7 @@ int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, co return gl[p_glyph | mod].texture_idx; } -void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { +void TextServerFallback::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1890,7 +1905,7 @@ void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const gl[p_glyph].found = true; } -RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, RID()); @@ -1901,7 +1916,7 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1938,7 +1953,7 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const return RID(); } -Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Size2()); @@ -1949,7 +1964,7 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con int mod = 0; if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { mod = (layout << 24); } @@ -1986,7 +2001,7 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con return Size2(); } -Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { +Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2036,7 +2051,7 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in #endif } -TypedArray<Vector2i> TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { +TypedArray<Vector2i> TextServerFallback::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); @@ -2052,7 +2067,7 @@ TypedArray<Vector2i> TextServerFallback::font_get_kerning_list(const RID &p_font return ret; } -void TextServerFallback::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { +void TextServerFallback::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2063,7 +2078,7 @@ void TextServerFallback::font_clear_kerning_map(const RID &p_font_rid, int64_t p fd->cache[size]->kerning_map.clear(); } -void TextServerFallback::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { +void TextServerFallback::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2074,7 +2089,7 @@ void TextServerFallback::font_remove_kerning(const RID &p_font_rid, int64_t p_si fd->cache[size]->kerning_map.erase(p_glyph_pair); } -void TextServerFallback::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { +void TextServerFallback::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2085,7 +2100,7 @@ void TextServerFallback::font_set_kerning(const RID &p_font_rid, int64_t p_size, fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; } -Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { +Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2120,12 +2135,12 @@ Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_si return Vector2(); } -int64_t TextServerFallback::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { +int64_t TextServerFallback::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); return (int64_t)p_char; } -bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) const { +bool TextServerFallback::_font_has_char(const RID &p_font_rid, int64_t p_char) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); if (!fd) { @@ -2146,7 +2161,7 @@ bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) co return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; } -String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const { +String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -2179,7 +2194,7 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const return chars; } -void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { +void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + "."); @@ -2214,7 +2229,7 @@ void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i } } -void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { +void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2245,7 +2260,7 @@ void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i #endif } -void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { +void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2260,7 +2275,7 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can if (!fd->msdf && fd->cache[size]->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -2337,7 +2352,7 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can } } -void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { +void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2352,7 +2367,7 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI if (!fd->msdf && fd->cache[size]->face) { // LCD layout, bits 24, 25, 26 if (fd->antialiasing == FONT_ANTIALIASING_LCD) { - TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"); + TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout"); if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) { lcd_aa = true; index = index | (layout << 24); @@ -2429,7 +2444,7 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI } } -bool TextServerFallback::font_is_language_supported(const RID &p_font_rid, const String &p_language) const { +bool TextServerFallback::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2441,7 +2456,7 @@ bool TextServerFallback::font_is_language_supported(const RID &p_font_rid, const } } -void TextServerFallback::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { +void TextServerFallback::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2449,7 +2464,7 @@ void TextServerFallback::font_set_language_support_override(const RID &p_font_ri fd->language_support_overrides[p_language] = p_supported; } -bool TextServerFallback::font_get_language_support_override(const RID &p_font_rid, const String &p_language) { +bool TextServerFallback::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2457,7 +2472,7 @@ bool TextServerFallback::font_get_language_support_override(const RID &p_font_ri return fd->language_support_overrides[p_language]; } -void TextServerFallback::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { +void TextServerFallback::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2465,7 +2480,7 @@ void TextServerFallback::font_remove_language_support_override(const RID &p_font fd->language_support_overrides.erase(p_language); } -PackedStringArray TextServerFallback::font_get_language_support_overrides(const RID &p_font_rid) { +PackedStringArray TextServerFallback::_font_get_language_support_overrides(const RID &p_font_rid) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedStringArray()); @@ -2477,7 +2492,7 @@ PackedStringArray TextServerFallback::font_get_language_support_overrides(const return out; } -bool TextServerFallback::font_is_script_supported(const RID &p_font_rid, const String &p_script) const { +bool TextServerFallback::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2489,7 +2504,7 @@ bool TextServerFallback::font_is_script_supported(const RID &p_font_rid, const S } } -void TextServerFallback::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { +void TextServerFallback::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2497,7 +2512,7 @@ void TextServerFallback::font_set_script_support_override(const RID &p_font_rid, fd->script_support_overrides[p_script] = p_supported; } -bool TextServerFallback::font_get_script_support_override(const RID &p_font_rid, const String &p_script) { +bool TextServerFallback::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2505,7 +2520,7 @@ bool TextServerFallback::font_get_script_support_override(const RID &p_font_rid, return fd->script_support_overrides[p_script]; } -void TextServerFallback::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { +void TextServerFallback::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2515,7 +2530,7 @@ void TextServerFallback::font_remove_script_support_override(const RID &p_font_r fd->script_support_overrides.erase(p_script); } -PackedStringArray TextServerFallback::font_get_script_support_overrides(const RID &p_font_rid) { +PackedStringArray TextServerFallback::_font_get_script_support_overrides(const RID &p_font_rid) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedStringArray()); @@ -2527,7 +2542,7 @@ PackedStringArray TextServerFallback::font_get_script_support_overrides(const RI return out; } -void TextServerFallback::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { +void TextServerFallback::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2537,7 +2552,7 @@ void TextServerFallback::font_set_opentype_feature_overrides(const RID &p_font_r fd->feature_overrides = p_overrides; } -Dictionary TextServerFallback::font_get_opentype_feature_overrides(const RID &p_font_rid) const { +Dictionary TextServerFallback::_font_get_opentype_feature_overrides(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2545,11 +2560,11 @@ Dictionary TextServerFallback::font_get_opentype_feature_overrides(const RID &p_ return fd->feature_overrides; } -Dictionary TextServerFallback::font_supported_feature_list(const RID &p_font_rid) const { +Dictionary TextServerFallback::_font_supported_feature_list(const RID &p_font_rid) const { return Dictionary(); } -Dictionary TextServerFallback::font_supported_variation_list(const RID &p_font_rid) const { +Dictionary TextServerFallback::_font_supported_variation_list(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2559,11 +2574,11 @@ Dictionary TextServerFallback::font_supported_variation_list(const RID &p_font_r return fd->supported_varaitions; } -double TextServerFallback::font_get_global_oversampling() const { +double TextServerFallback::_font_get_global_oversampling() const { return oversampling; } -void TextServerFallback::font_set_global_oversampling(double p_oversampling) { +void TextServerFallback::_font_set_global_oversampling(double p_oversampling) { _THREAD_SAFE_METHOD_ if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -2571,8 +2586,8 @@ void TextServerFallback::font_set_global_oversampling(double p_oversampling) { font_owner.get_owned_list(&fonts); bool font_cleared = false; for (const RID &E : fonts) { - if (!font_is_multichannel_signed_distance_field(E) && font_get_oversampling(E) <= 0) { - font_clear_size_cache(E); + if (!_font_is_multichannel_signed_distance_field(E) && _font_get_oversampling(E) <= 0) { + _font_clear_size_cache(E); font_cleared = true; } } @@ -2627,7 +2642,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) { p_shaped->parent = RID(); } -RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { +RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback); @@ -2637,7 +2652,7 @@ RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, Te return shaped_owner.make_rid(sd); } -void TextServerFallback::shaped_text_clear(const RID &p_shaped) { +void TextServerFallback::_shaped_text_clear(const RID &p_shaped) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2651,21 +2666,21 @@ void TextServerFallback::shaped_text_clear(const RID &p_shaped) { invalidate(sd); } -void TextServerFallback::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { +void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { if (p_direction == DIRECTION_RTL) { ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server."); } } -TextServer::Direction TextServerFallback::shaped_text_get_direction(const RID &p_shaped) const { +TextServer::Direction TextServerFallback::_shaped_text_get_direction(const RID &p_shaped) const { return TextServer::DIRECTION_LTR; } -TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(const RID &p_shaped) const { +TextServer::Direction TextServerFallback::_shaped_text_get_inferred_direction(const RID &p_shaped) const { return TextServer::DIRECTION_LTR; } -void TextServerFallback::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { +void TextServerFallback::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2679,14 +2694,14 @@ void TextServerFallback::shaped_text_set_custom_punctuation(const RID &p_shaped, } } -String TextServerFallback::shaped_text_get_custom_punctuation(const RID &p_shaped) const { +String TextServerFallback::_shaped_text_get_custom_punctuation(const RID &p_shaped) const { _THREAD_SAFE_METHOD_ const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, String()); return sd->custom_punct; } -void TextServerFallback::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { +void TextServerFallback::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2700,11 +2715,11 @@ void TextServerFallback::shaped_text_set_orientation(const RID &p_shaped, TextSe } } -void TextServerFallback::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { +void TextServerFallback::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { // No BiDi support, ignore. } -TextServer::Orientation TextServerFallback::shaped_text_get_orientation(const RID &p_shaped) const { +TextServer::Orientation TextServerFallback::_shaped_text_get_orientation(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL); @@ -2712,7 +2727,7 @@ TextServer::Orientation TextServerFallback::shaped_text_get_orientation(const RI return sd->orientation; } -void TextServerFallback::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { +void TextServerFallback::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); MutexLock lock(sd->mutex); @@ -2726,7 +2741,7 @@ void TextServerFallback::shaped_text_set_preserve_invalid(const RID &p_shaped, b } } -bool TextServerFallback::shaped_text_get_preserve_invalid(const RID &p_shaped) const { +bool TextServerFallback::_shaped_text_get_preserve_invalid(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -2734,7 +2749,7 @@ bool TextServerFallback::shaped_text_get_preserve_invalid(const RID &p_shaped) c return sd->preserve_invalid; } -void TextServerFallback::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { +void TextServerFallback::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2748,7 +2763,7 @@ void TextServerFallback::shaped_text_set_preserve_control(const RID &p_shaped, b } } -bool TextServerFallback::shaped_text_get_preserve_control(const RID &p_shaped) const { +bool TextServerFallback::_shaped_text_get_preserve_control(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -2756,7 +2771,7 @@ bool TextServerFallback::shaped_text_get_preserve_control(const RID &p_shaped) c return sd->preserve_control; } -void TextServerFallback::shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) { +void TextServerFallback::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) { ERR_FAIL_INDEX((int)p_spacing, 4); ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2771,7 +2786,7 @@ void TextServerFallback::shaped_text_set_spacing(const RID &p_shaped, SpacingTyp } } -int64_t TextServerFallback::shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const { +int64_t TextServerFallback::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const { ERR_FAIL_INDEX_V((int)p_spacing, 4, 0); const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); @@ -2781,20 +2796,20 @@ int64_t TextServerFallback::shaped_text_get_spacing(const RID &p_shaped, Spacing return sd->extra_spacing[p_spacing]; } -int64_t TextServerFallback::shaped_get_span_count(const RID &p_shaped) const { +int64_t TextServerFallback::_shaped_get_span_count(const RID &p_shaped) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); return sd->spans.size(); } -Variant TextServerFallback::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { +Variant TextServerFallback::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Variant()); ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant()); return sd->spans[p_index].meta; } -void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { +void TextServerFallback::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); ERR_FAIL_INDEX(p_index, sd->spans.size()); @@ -2805,7 +2820,7 @@ void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_ Array fonts_no_match; int font_count = p_fonts.size(); for (int i = 0; i < font_count; i++) { - if (font_is_language_supported(p_fonts[i], span.language)) { + if (_font_is_language_supported(p_fonts[i], span.language)) { span.fonts.push_back(p_fonts[i]); } else { fonts_no_match.push_back(p_fonts[i]); @@ -2818,7 +2833,7 @@ void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_ sd->valid = false; } -bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { +bool TextServerFallback::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -2844,8 +2859,11 @@ bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const Strin // Pre-sort fonts, push fonts with the language support first. Array fonts_no_match; int font_count = p_fonts.size(); - for (int i = 0; i < font_count; i++) { - if (font_is_language_supported(p_fonts[i], p_language)) { + if (font_count > 0) { + span.fonts.push_back(p_fonts[0]); + } + for (int i = 1; i < font_count; i++) { + if (_font_is_language_supported(p_fonts[i], p_language)) { span.fonts.push_back(p_fonts[i]); } else { fonts_no_match.push_back(p_fonts[i]); @@ -2866,7 +2884,7 @@ bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const Strin return true; } -bool TextServerFallback::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { +bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -2897,7 +2915,7 @@ bool TextServerFallback::shaped_text_add_object(const RID &p_shaped, const Varia return true; } -bool TextServerFallback::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { +bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -2938,14 +2956,14 @@ bool TextServerFallback::shaped_text_resize_object(const RID &p_shaped, const Va } else { if (gl.font_rid.is_valid()) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, font_get_ascent(gl.font_rid, gl.font_size)); - sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size)); + sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size)); + sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size)); } else { - sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - sd->descent = MAX(sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size)); + sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { @@ -3032,7 +3050,7 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const { p_sd->descent = full_descent; } -RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { +RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { _THREAD_SAFE_METHOD_ const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); @@ -3040,10 +3058,10 @@ RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, MutexLock lock(sd->mutex); if (sd->parent != RID()) { - return shaped_text_substr(sd->parent, p_start, p_length); + return _shaped_text_substr(sd->parent, p_start, p_length); } if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID()); ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID()); @@ -3098,11 +3116,11 @@ RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, } else { if (gl.font_rid.is_valid()) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, font_get_ascent(gl.font_rid, gl.font_size)); - new_sd->descent = MAX(new_sd->descent, font_get_descent(gl.font_rid, gl.font_size)); + new_sd->ascent = MAX(new_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size)); + new_sd->descent = MAX(new_sd->descent, _font_get_descent(gl.font_rid, gl.font_size)); } else { - new_sd->ascent = MAX(new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - new_sd->descent = MAX(new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + new_sd->ascent = MAX(new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. @@ -3126,7 +3144,7 @@ RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, return shaped_owner.make_rid(new_sd); } -RID TextServerFallback::shaped_text_get_parent(const RID &p_shaped) const { +RID TextServerFallback::_shaped_text_get_parent(const RID &p_shaped) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); @@ -3134,16 +3152,16 @@ RID TextServerFallback::shaped_text_get_parent(const RID &p_shaped) const { return sd->parent; } -double TextServerFallback::shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<JustificationFlag> p_jst_flags) { +double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<JustificationFlag> p_jst_flags) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } if (!sd->justification_ops_valid) { - const_cast<TextServerFallback *>(this)->shaped_text_update_justification_ops(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_update_justification_ops(p_shaped); } int start_pos = 0; @@ -3243,16 +3261,16 @@ double TextServerFallback::shaped_text_fit_to_width(const RID &p_shaped, double return Math::ceil(justification_width); } -double TextServerFallback::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { +double TextServerFallback::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { - const_cast<TextServerFallback *>(this)->shaped_text_update_breaks(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_update_breaks(p_shaped); } for (int i = 0; i < p_tab_stops.size(); i++) { @@ -3299,13 +3317,13 @@ double TextServerFallback::shaped_text_tab_align(const RID &p_shaped, const Pack return 0.0; } -bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) { +bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped); + _shaped_text_shape(p_shaped); } if (sd->line_breaks_valid) { @@ -3355,29 +3373,29 @@ bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) { return sd->line_breaks_valid; } -bool TextServerFallback::shaped_text_update_justification_ops(const RID &p_shaped) { +bool TextServerFallback::_shaped_text_update_justification_ops(const RID &p_shaped) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped); + _shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { - shaped_text_update_breaks(p_shaped); + _shaped_text_update_breaks(p_shaped); } sd->justification_ops_valid = true; // Not supported by fallback server. return true; } -void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { +void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid."); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped_line); + _shaped_text_shape(p_shaped_line); } sd->text_trimmed = false; @@ -3416,30 +3434,30 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l // Find usable fonts, if fonts from the last glyph do not have required chars. RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!font_has_char(dot_gl_font_rid, '.')) { + if (!_font_has_char(dot_gl_font_rid, '.')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (font_has_char(fonts[i], '.')) { + if (_font_has_char(fonts[i], '.')) { dot_gl_font_rid = fonts[i]; break; } } } RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!font_has_char(whitespace_gl_font_rid, '.')) { + if (!_font_has_char(whitespace_gl_font_rid, '.')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (font_has_char(fonts[i], ' ')) { + if (_font_has_char(fonts[i], ' ')) { whitespace_gl_font_rid = fonts[i]; break; } } } - int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; - Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); - int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; - Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { @@ -3528,7 +3546,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l } } -int64_t TextServerFallback::shaped_text_get_trim_pos(const RID &p_shaped) const { +int64_t TextServerFallback::_shaped_text_get_trim_pos(const RID &p_shaped) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid."); @@ -3536,7 +3554,7 @@ int64_t TextServerFallback::shaped_text_get_trim_pos(const RID &p_shaped) const return sd->overrun_trim_data.trim_pos; } -int64_t TextServerFallback::shaped_text_get_ellipsis_pos(const RID &p_shaped) const { +int64_t TextServerFallback::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid."); @@ -3544,7 +3562,7 @@ int64_t TextServerFallback::shaped_text_get_ellipsis_pos(const RID &p_shaped) co return sd->overrun_trim_data.ellipsis_pos; } -const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { +const Glyph *TextServerFallback::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataFallback invalid."); @@ -3552,7 +3570,7 @@ const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(const RID &p_sh return sd->overrun_trim_data.ellipsis_glyph_buf.ptr(); } -int64_t TextServerFallback::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { +int64_t TextServerFallback::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataFallback invalid."); @@ -3560,7 +3578,7 @@ int64_t TextServerFallback::shaped_text_get_ellipsis_glyph_count(const RID &p_sh return sd->overrun_trim_data.ellipsis_glyph_buf.size(); } -bool TextServerFallback::shaped_text_shape(const RID &p_shaped) { +bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3627,27 +3645,27 @@ bool TextServerFallback::shaped_text_shape(const RID &p_shaped) { } // Select first font which has character (font are already sorted by span language). for (int k = 0; k < span.fonts.size(); k++) { - if (font_has_char(span.fonts[k], gl.index)) { + if (_font_has_char(span.fonts[k], gl.index)) { gl.font_rid = span.fonts[k]; break; } } if (gl.font_rid.is_valid()) { - bool subpos = (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); + bool subpos = (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x); + gl.advance = Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x); gl.x_off = 0; gl.y_off = 0; - sd->ascent = MAX(sd->ascent, font_get_ascent(gl.font_rid, gl.font_size)); - sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size)); + sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size)); + sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size)); } else { - gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y); - gl.x_off = -Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5); - gl.y_off = font_get_ascent(gl.font_rid, gl.font_size); - sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - sd->descent = MAX(sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + gl.advance = Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y); + gl.x_off = -Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5); + gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size); + sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } } if (j < sd->end - 1) { @@ -3658,17 +3676,17 @@ bool TextServerFallback::shaped_text_shape(const RID &p_shaped) { gl.advance += sd->extra_spacing[SPACING_GLYPH]; } } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size)); + sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size)); // Add kerning to previous glyph. if (sd->glyphs.size() > 0) { Glyph &prev_gl = sd->glyphs.write[sd->glyphs.size() - 1]; if (prev_gl.font_rid == gl.font_rid && prev_gl.font_size == gl.font_size) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - prev_gl.advance += font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).x; + prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).x; } else { - prev_gl.advance += font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).y; + prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).y; } } } @@ -3699,7 +3717,7 @@ bool TextServerFallback::shaped_text_shape(const RID &p_shaped) { return sd->valid; } -bool TextServerFallback::shaped_text_is_ready(const RID &p_shaped) const { +bool TextServerFallback::_shaped_text_is_ready(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3707,41 +3725,41 @@ bool TextServerFallback::shaped_text_is_ready(const RID &p_shaped) const { return sd->valid; } -const Glyph *TextServerFallback::shaped_text_get_glyphs(const RID &p_shaped) const { +const Glyph *TextServerFallback::_shaped_text_get_glyphs(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.ptr(); } -int64_t TextServerFallback::shaped_text_get_glyph_count(const RID &p_shaped) const { +int64_t TextServerFallback::_shaped_text_get_glyph_count(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.size(); } -const Glyph *TextServerFallback::shaped_text_sort_logical(const RID &p_shaped) { +const Glyph *TextServerFallback::_shaped_text_sort_logical(const RID &p_shaped) { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.ptr(); // Already in the logical order, return as is. } -Vector2i TextServerFallback::shaped_text_get_range(const RID &p_shaped) const { +Vector2i TextServerFallback::_shaped_text_get_range(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Vector2i()); @@ -3749,7 +3767,7 @@ Vector2i TextServerFallback::shaped_text_get_range(const RID &p_shaped) const { return Vector2(sd->start, sd->end); } -Array TextServerFallback::shaped_text_get_objects(const RID &p_shaped) const { +Array TextServerFallback::_shaped_text_get_objects(const RID &p_shaped) const { Array ret; const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, ret); @@ -3762,25 +3780,25 @@ Array TextServerFallback::shaped_text_get_objects(const RID &p_shaped) const { return ret; } -Rect2 TextServerFallback::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { +Rect2 TextServerFallback::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Rect2()); MutexLock lock(sd->mutex); ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2()); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->objects[p_key].rect; } -Size2 TextServerFallback::shaped_text_get_size(const RID &p_shaped) const { +Size2 TextServerFallback::_shaped_text_get_size(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Size2()); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { return Size2(sd->width, sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil(); @@ -3789,64 +3807,64 @@ Size2 TextServerFallback::shaped_text_get_size(const RID &p_shaped) const { } } -double TextServerFallback::shaped_text_get_ascent(const RID &p_shaped) const { +double TextServerFallback::_shaped_text_get_ascent(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->ascent + sd->extra_spacing[SPACING_TOP]; } -double TextServerFallback::shaped_text_get_descent(const RID &p_shaped) const { +double TextServerFallback::_shaped_text_get_descent(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->descent + sd->extra_spacing[SPACING_BOTTOM]; } -double TextServerFallback::shaped_text_get_width(const RID &p_shaped) const { +double TextServerFallback::_shaped_text_get_width(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return Math::ceil(sd->width); } -double TextServerFallback::shaped_text_get_underline_position(const RID &p_shaped) const { +double TextServerFallback::_shaped_text_get_underline_position(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->upos; } -double TextServerFallback::shaped_text_get_underline_thickness(const RID &p_shaped) const { +double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_shaped) const { const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped); } return sd->uthk; } -String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const { +String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const { String upper = p_string; for (int i = 0; i <= upper.length(); i++) { @@ -3860,7 +3878,7 @@ String TextServerFallback::string_to_upper(const String &p_string, const String return upper; } -String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const { +String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const { String lower = p_string; for (int i = 0; i <= lower.length(); i++) { @@ -3874,7 +3892,7 @@ String TextServerFallback::string_to_lower(const String &p_string, const String return lower; } -PackedInt32Array TextServerFallback::string_get_word_breaks(const String &p_string, const String &p_language) const { +PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language) const { PackedInt32Array ret; for (int i = 0; i < p_string.length(); i++) { char32_t c = p_string[i]; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index cbb2fb03f2..4aeec4f452 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -42,6 +42,7 @@ #include <godot_cpp/godot.hpp> #include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/ext_wrappers.gen.inc> #include <godot_cpp/core/mutex_lock.hpp> #include <godot_cpp/variant/array.hpp> @@ -52,6 +53,7 @@ #include <godot_cpp/variant/rect2.hpp> #include <godot_cpp/variant/rid.hpp> #include <godot_cpp/variant/string.hpp> +#include <godot_cpp/variant/typed_array.hpp> #include <godot_cpp/variant/vector2.hpp> #include <godot_cpp/variant/vector2i.hpp> @@ -79,6 +81,7 @@ using namespace godot; #include "servers/text/text_server_extension.h" +#include "core/extension/ext_wrappers.gen.inc" #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" @@ -337,251 +340,249 @@ protected: void invalidate(ShapedTextDataFallback *p_shaped); public: - virtual bool has_feature(Feature p_feature) const override; - virtual String get_name() const override; - virtual int64_t get_features() const override; + MODBIND1RC(bool, has_feature, Feature); + MODBIND0RC(String, get_name); + MODBIND0RC(int64_t, get_features); - virtual void free_rid(const RID &p_rid) override; - virtual bool has(const RID &p_rid) override; - virtual bool load_support_data(const String &p_filename) override; + MODBIND1(free_rid, const RID &); + MODBIND1R(bool, has, const RID &); + MODBIND1R(bool, load_support_data, const String &); - 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; + MODBIND0RC(String, get_support_data_filename); + MODBIND0RC(String, get_support_data_info); + MODBIND1RC(bool, save_support_data, const String &); - virtual bool is_locale_right_to_left(const String &p_locale) const override; + MODBIND1RC(bool, is_locale_right_to_left, const String &); - virtual int64_t name_to_tag(const String &p_name) const override; - virtual String tag_to_name(int64_t p_tag) const override; + MODBIND1RC(int64_t, name_to_tag, const String &); + MODBIND1RC(String, tag_to_name, int64_t); /* Font interface */ - virtual RID create_font() override; - virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; - virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + MODBIND0R(RID, create_font); + + MODBIND2(font_set_data, const RID &, const PackedByteArray &); + MODBIND3(font_set_data_ptr, const RID &, const uint8_t *, int64_t); + + MODBIND2(font_set_face_index, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_face_index, const RID &); - virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override; - virtual int64_t font_get_face_index(const RID &p_font_rid) const override; + MODBIND1RC(int64_t, font_get_face_count, const RID &); - virtual int64_t font_get_face_count(const RID &p_font_rid) const override; + MODBIND2(font_set_style, const RID &, BitField<FontStyle>); + MODBIND1RC(BitField<FontStyle>, font_get_style, const RID &); - virtual void font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) override; - virtual BitField<FontStyle> font_get_style(const RID &p_font_rid) const override; + MODBIND2(font_set_style_name, const RID &, const String &); + MODBIND1RC(String, font_get_style_name, const RID &); - virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override; - virtual String font_get_style_name(const RID &p_font_rid) const override; + MODBIND2(font_set_name, const RID &, const String &); + MODBIND1RC(String, font_get_name, const RID &); - virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; - virtual String font_get_name(const RID &p_font_rid) const override; + MODBIND2(font_set_antialiasing, const RID &, TextServer::FontAntialiasing); + MODBIND1RC(TextServer::FontAntialiasing, font_get_antialiasing, const RID &); - virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; - virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override; + MODBIND2(font_set_generate_mipmaps, const RID &, bool); + MODBIND1RC(bool, font_get_generate_mipmaps, const RID &); - virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; - virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; + MODBIND2(font_set_multichannel_signed_distance_field, const RID &, bool); + MODBIND1RC(bool, font_is_multichannel_signed_distance_field, const RID &); - virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override; - virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override; + MODBIND2(font_set_msdf_pixel_range, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_msdf_pixel_range, const RID &); - virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override; - virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override; + MODBIND2(font_set_msdf_size, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_msdf_size, const RID &); - virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override; - virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override; + MODBIND2(font_set_fixed_size, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_fixed_size, const RID &); - virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override; - virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override; + MODBIND2(font_set_force_autohinter, const RID &, bool); + MODBIND1RC(bool, font_is_force_autohinter, const RID &); - virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override; - virtual bool font_is_force_autohinter(const RID &p_font_rid) const override; + MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning); + MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &); - virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override; - virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override; + MODBIND2(font_set_embolden, const RID &, double); + MODBIND1RC(double, font_get_embolden, const RID &); - virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override; - virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override; + MODBIND2(font_set_transform, const RID &, const Transform2D &); + MODBIND1RC(Transform2D, font_get_transform, const RID &); - virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override; - virtual double font_get_embolden(const RID &p_font_rid) const override; + MODBIND2(font_set_variation_coordinates, const RID &, const Dictionary &); + MODBIND1RC(Dictionary, font_get_variation_coordinates, const RID &); - virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override; - virtual Transform2D font_get_transform(const RID &p_font_rid) const override; + MODBIND2(font_set_hinting, const RID &, TextServer::Hinting); + MODBIND1RC(TextServer::Hinting, font_get_hinting, const RID &); - virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override; - virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override; + MODBIND2(font_set_oversampling, const RID &, double); + MODBIND1RC(double, font_get_oversampling, const RID &); - virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; - virtual double font_get_oversampling(const RID &p_font_rid) const override; + MODBIND1RC(TypedArray<Vector2i>, font_get_size_cache_list, const RID &); + MODBIND1(font_clear_size_cache, const RID &); + MODBIND2(font_remove_size_cache, const RID &, const Vector2i &); - virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override; - virtual void font_clear_size_cache(const RID &p_font_rid) override; - virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; + MODBIND3(font_set_ascent, const RID &, int64_t, double); + MODBIND2RC(double, font_get_ascent, const RID &, int64_t); - virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override; - virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_descent, const RID &, int64_t, double); + MODBIND2RC(double, font_get_descent, const RID &, int64_t); - virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override; - virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_underline_position, const RID &, int64_t, double); + MODBIND2RC(double, font_get_underline_position, const RID &, int64_t); - virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override; - virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_underline_thickness, const RID &, int64_t, double); + MODBIND2RC(double, font_get_underline_thickness, const RID &, int64_t); - virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override; - virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_scale, const RID &, int64_t, double); + MODBIND2RC(double, font_get_scale, const RID &, int64_t); - virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override; - virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override; + MODBIND2RC(int64_t, font_get_texture_count, const RID &, const Vector2i &); + MODBIND2(font_clear_textures, const RID &, const Vector2i &); + MODBIND3(font_remove_texture, const RID &, const Vector2i &, int64_t); - virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override; + MODBIND4(font_set_texture_image, const RID &, const Vector2i &, int64_t, const Ref<Image> &); + MODBIND3RC(Ref<Image>, font_get_texture_image, const RID &, const Vector2i &, int64_t); - virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override; - virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; + MODBIND4(font_set_texture_offsets, const RID &, const Vector2i &, int64_t, const PackedInt32Array &); + MODBIND3RC(PackedInt32Array, font_get_texture_offsets, const RID &, const Vector2i &, int64_t); - virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; - virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; + MODBIND2RC(PackedInt32Array, font_get_glyph_list, const RID &, const Vector2i &); + MODBIND2(font_clear_glyphs, const RID &, const Vector2i &); + MODBIND3(font_remove_glyph, const RID &, const Vector2i &, int64_t); - virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; + MODBIND3RC(Vector2, font_get_glyph_advance, const RID &, int64_t, int64_t); + MODBIND4(font_set_glyph_advance, const RID &, int64_t, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override; + MODBIND3RC(Vector2, font_get_glyph_offset, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_offset, const RID &, const Vector2i &, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override; + MODBIND3RC(Vector2, font_get_glyph_size, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_size, const RID &, const Vector2i &, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override; + MODBIND3RC(Rect2, font_get_glyph_uv_rect, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_uv_rect, const RID &, const Vector2i &, int64_t, const Rect2 &); - virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override; + MODBIND3RC(int64_t, font_get_glyph_texture_idx, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_texture_idx, const RID &, const Vector2i &, int64_t, int64_t); - virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override; - virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + MODBIND3RC(RID, font_get_glyph_texture_rid, const RID &, const Vector2i &, int64_t); + MODBIND3RC(Size2, font_get_glyph_texture_size, const RID &, const Vector2i &, int64_t); - virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; + MODBIND3RC(Dictionary, font_get_glyph_contours, const RID &, int64_t, int64_t); - virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; - virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; + MODBIND2RC(TypedArray<Vector2i>, font_get_kerning_list, const RID &, int64_t); + MODBIND2(font_clear_kerning_map, const RID &, int64_t); + MODBIND3(font_remove_kerning, const RID &, int64_t, const Vector2i &); - virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; - virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override; + MODBIND4(font_set_kerning, const RID &, int64_t, const Vector2i &, const Vector2 &); + MODBIND3RC(Vector2, font_get_kerning, const RID &, int64_t, const Vector2i &); - virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override; + MODBIND4RC(int64_t, font_get_glyph_index, const RID &, int64_t, int64_t, int64_t); - virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override; - virtual String font_get_supported_chars(const RID &p_font_rid) const override; + MODBIND2RC(bool, font_has_char, const RID &, int64_t); + MODBIND1RC(String, font_get_supported_chars, const RID &); - virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override; - virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override; + MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t); + MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t); - virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + MODBIND6C(font_draw_glyph, const RID &, const RID &, int64_t, const Vector2 &, int64_t, const Color &); + MODBIND7C(font_draw_glyph_outline, const RID &, const RID &, int64_t, int64_t, const Vector2 &, int64_t, const Color &); - virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override; - virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override; - virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override; - virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override; - virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override; + MODBIND2RC(bool, font_is_language_supported, const RID &, const String &); + MODBIND3(font_set_language_support_override, const RID &, const String &, bool); + MODBIND2R(bool, font_get_language_support_override, const RID &, const String &); + MODBIND2(font_remove_language_support_override, const RID &, const String &); + MODBIND1R(PackedStringArray, font_get_language_support_overrides, const RID &); - virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override; - virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override; - virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override; - virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override; - virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override; + MODBIND2RC(bool, font_is_script_supported, const RID &, const String &); + MODBIND3(font_set_script_support_override, const RID &, const String &, bool); + MODBIND2R(bool, font_get_script_support_override, const RID &, const String &); + MODBIND2(font_remove_script_support_override, const RID &, const String &); + MODBIND1R(PackedStringArray, font_get_script_support_overrides, const RID &); - virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override; - virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override; + MODBIND2(font_set_opentype_feature_overrides, const RID &, const Dictionary &); + MODBIND1RC(Dictionary, font_get_opentype_feature_overrides, const RID &); - virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override; - virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override; + MODBIND1RC(Dictionary, font_supported_feature_list, const RID &); + MODBIND1RC(Dictionary, font_supported_variation_list, const RID &); - virtual double font_get_global_oversampling() const override; - virtual void font_set_global_oversampling(double p_oversampling) override; + MODBIND0RC(double, font_get_global_oversampling); + MODBIND1(font_set_global_oversampling, double); /* Shaped text buffer interface */ - virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + MODBIND2R(RID, create_shaped_text, Direction, Orientation); - virtual void shaped_text_clear(const RID &p_shaped) override; + MODBIND1(shaped_text_clear, const RID &); - virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override; - virtual Direction shaped_text_get_direction(const RID &p_shaped) const override; - virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_direction, const RID &, Direction); + MODBIND1RC(Direction, shaped_text_get_direction, const RID &); + MODBIND1RC(Direction, shaped_text_get_inferred_direction, const RID &); - virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override; + MODBIND2(shaped_text_set_bidi_override, const RID &, const Array &); - virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override; - virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_custom_punctuation, const RID &, const String &); + MODBIND1RC(String, shaped_text_get_custom_punctuation, const RID &); - virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_orientation, const RID &, Orientation); + MODBIND1RC(Orientation, shaped_text_get_orientation, const RID &); - virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_preserve_invalid, const RID &, bool); + MODBIND1RC(bool, shaped_text_get_preserve_invalid, const RID &); - virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_preserve_control, const RID &, bool); + MODBIND1RC(bool, shaped_text_get_preserve_control, const RID &); - virtual void shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) override; - virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const override; + MODBIND3(shaped_text_set_spacing, const RID &, SpacingType, int64_t); + MODBIND2RC(int64_t, shaped_text_get_spacing, const RID &, SpacingType); - virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; - virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override; - virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; + MODBIND7R(bool, shaped_text_add_string, const RID &, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &); + MODBIND5R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t); + MODBIND4R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment); - virtual int64_t shaped_get_span_count(const RID &p_shaped) const override; - virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override; - virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override; + MODBIND1RC(int64_t, shaped_get_span_count, const RID &); + MODBIND2RC(Variant, shaped_get_span_meta, const RID &, int64_t); + MODBIND5(shaped_set_span_update_font, const RID &, int64_t, const TypedArray<RID> &, int64_t, const Dictionary &); - virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override; - virtual RID shaped_text_get_parent(const RID &p_shaped) const override; + MODBIND3RC(RID, shaped_text_substr, const RID &, int64_t, int64_t); + MODBIND1RC(RID, shaped_text_get_parent, const RID &); - virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; - virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override; + MODBIND3R(double, shaped_text_fit_to_width, const RID &, double, BitField<TextServer::JustificationFlag>); + MODBIND2R(double, shaped_text_tab_align, const RID &, const PackedFloat32Array &); - virtual bool shaped_text_shape(const RID &p_shaped) override; - virtual bool shaped_text_update_breaks(const RID &p_shaped) override; - virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override; + MODBIND1R(bool, shaped_text_shape, const RID &); + MODBIND1R(bool, shaped_text_update_breaks, const RID &); + MODBIND1R(bool, shaped_text_update_justification_ops, const RID &); - virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override; - virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override; - virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override; + MODBIND1RC(int64_t, shaped_text_get_trim_pos, const RID &); + MODBIND1RC(int64_t, shaped_text_get_ellipsis_pos, const RID &); + MODBIND1RC(const Glyph *, shaped_text_get_ellipsis_glyphs, const RID &); + MODBIND1RC(int64_t, shaped_text_get_ellipsis_glyph_count, const RID &); - virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) override; + MODBIND3(shaped_text_overrun_trim_to_width, const RID &, double, BitField<TextServer::TextOverrunFlag>); - virtual bool shaped_text_is_ready(const RID &p_shaped) const override; + MODBIND1RC(bool, shaped_text_is_ready, const RID &); - virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override; - virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override; + MODBIND1RC(const Glyph *, shaped_text_get_glyphs, const RID &); + MODBIND1R(const Glyph *, shaped_text_sort_logical, const RID &); + MODBIND1RC(int64_t, shaped_text_get_glyph_count, const RID &); - virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override; + MODBIND1RC(Vector2i, shaped_text_get_range, const RID &); - virtual Array shaped_text_get_objects(const RID &p_shaped) const override; - virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override; + MODBIND1RC(Array, shaped_text_get_objects, const RID &); + MODBIND2RC(Rect2, shaped_text_get_object_rect, const RID &, const Variant &); - virtual Size2 shaped_text_get_size(const RID &p_shaped) const override; - virtual double shaped_text_get_ascent(const RID &p_shaped) const override; - virtual double shaped_text_get_descent(const RID &p_shaped) const override; - virtual double shaped_text_get_width(const RID &p_shaped) const override; - virtual double shaped_text_get_underline_position(const RID &p_shaped) const override; - virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override; + MODBIND1RC(Size2, shaped_text_get_size, const RID &); + MODBIND1RC(double, shaped_text_get_ascent, const RID &); + MODBIND1RC(double, shaped_text_get_descent, const RID &); + MODBIND1RC(double, shaped_text_get_width, const RID &); + MODBIND1RC(double, shaped_text_get_underline_position, const RID &); + MODBIND1RC(double, shaped_text_get_underline_thickness, const RID &); - virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override; + MODBIND2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &); - virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; - virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + MODBIND2RC(String, string_to_upper, const String &, const String &); + MODBIND2RC(String, string_to_lower, const String &, const String &); TextServerFallback(); ~TextServerFallback(); diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 00ba32eae1..aed95294e7 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -100,7 +100,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff uint32_t width = p_header.image_width; uint32_t height = p_header.image_height; tga_origin_e origin = static_cast<tga_origin_e>((p_header.image_descriptor & TGA_ORIGIN_MASK) >> TGA_ORIGIN_SHIFT); - + uint8_t alpha_bits = p_header.image_descriptor & TGA_IMAGE_DESCRIPTOR_ALPHA_MASK; uint32_t x_start; int32_t x_step; uint32_t x_end; @@ -184,6 +184,27 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff y += y_step; } } + } else if (p_header.pixel_depth == 16) { + while (y != y_end) { + while (x != x_end) { + if (i + 1 >= p_input_size) { + return ERR_PARSE_ERROR; + } + + // Always stored as RGBA5551 + uint8_t r = (p_buffer[i + 1] & 0x7c) << 1; + uint8_t g = ((p_buffer[i + 1] & 0x03) << 6) | ((p_buffer[i + 0] & 0xe0) >> 2); + uint8_t b = (p_buffer[i + 0] & 0x1f) << 3; + uint8_t a = (p_buffer[i + 1] & 0x80) ? 0xff : 0; + + TGA_PUT_PIXEL(r, g, b, alpha_bits ? a : 0xff); + + x += x_step; + i += 2; + } + x = x_start; + y += y_step; + } } else if (p_header.pixel_depth == 24) { while (y != y_end) { while (x != x_end) { @@ -277,7 +298,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField err = FAILED; } - if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) { + if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 16 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) { err = FAILED; } diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index b257ed110d..de964373ed 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -33,6 +33,8 @@ #include "core/io/image_loader.h" +#define TGA_IMAGE_DESCRIPTOR_ALPHA_MASK 0xf + class ImageLoaderTGA : public ImageFormatLoader { enum tga_type_e { TGA_TYPE_NO_DATA = 0, diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index c4462ba687..57f055ca42 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -91,8 +91,6 @@ void VideoStreamPlaybackTheora::video_write() { uint8_t *w = frame_data.ptrw(); char *dst = (char *)w; - //uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2); - if (px_fmt == TH_PF_444) { yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2); @@ -101,7 +99,7 @@ void VideoStreamPlaybackTheora::video_write() { } else if (px_fmt == TH_PF_420) { yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2); - }; + } format = Image::FORMAT_RGBA8; } @@ -123,7 +121,7 @@ void VideoStreamPlaybackTheora::clear() { if (vorbis_p >= 3) { vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); - }; + } vorbis_comment_clear(&vc); vorbis_info_clear(&vi); vorbis_p = 0; @@ -154,7 +152,7 @@ void VideoStreamPlaybackTheora::clear() { file.unref(); playing = false; -}; +} void VideoStreamPlaybackTheora::set_file(const String &p_file) { ERR_FAIL_COND(playing); @@ -174,7 +172,6 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { ring_buffer.write(read_buffer.ptr(), read); thread.start(_streaming_thread, this); - #endif ogg_sync_init(&oy); @@ -245,6 +242,12 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { /* we're expecting more header packets. */ while ((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3)) { +#ifdef _MSC_VER + // Make exception for these assignments in conditional expression. +#pragma warning(push) +#pragma warning(disable : 4706) +#endif + int ret; /* look for further theora headers */ @@ -281,6 +284,10 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { } } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + /* The header pages/packets will arrive before anything else we care about, or the stream is not obeying spec */ @@ -355,20 +362,20 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { buffering = true; time = 0; audio_frames_wrote = 0; -}; +} -float VideoStreamPlaybackTheora::get_time() const { +double VideoStreamPlaybackTheora::get_time() const { // FIXME: AudioServer output latency was fixed in af9bb0e, previously it used to // systematically return 0. Now that it gives a proper latency, it broke this // code where the delay compensation likely never really worked. return time - /* AudioServer::get_singleton()->get_output_latency() - */ delay_compensation; -}; +} Ref<Texture2D> VideoStreamPlaybackTheora::get_texture() const { return texture; } -void VideoStreamPlaybackTheora::update(float p_delta) { +void VideoStreamPlaybackTheora::update(double p_delta) { if (file.is_null()) { return; } @@ -376,7 +383,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { if (!playing || paused) { //printf("not playing\n"); return; - }; + } #ifdef THEORA_USE_THREAD_STREAMING thread_sem->post(); @@ -444,7 +451,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } } else { /* we need more data; break out to suck in another page */ break; - }; + } } audio_done = videobuf_time < (audio_frames_wrote / float(vi.rate)); @@ -507,7 +514,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { //printf("video done, stopping\n"); stop(); return; - }; + } if (!frame_done || !audio_done) { //what's the point of waiting for audio to grab a page? @@ -529,7 +536,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { //printf("frame at %f not ready (time %f), ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); } - float tdiff = videobuf_time - get_time(); + double tdiff = videobuf_time - get_time(); /*If we have lots of extra time, increase the post-processing level.*/ if (tdiff > ti.fps_denominator * 0.25 / ti.fps_numerator) { pp_inc = pp_level < pp_level_max ? 1 : 0; @@ -539,7 +546,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } video_write(); -}; +} void VideoStreamPlaybackTheora::play() { if (!playing) { @@ -551,7 +558,7 @@ void VideoStreamPlaybackTheora::play() { playing = true; delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms"); delay_compensation /= 1000.0; -}; +} void VideoStreamPlaybackTheora::stop() { if (playing) { @@ -560,44 +567,44 @@ void VideoStreamPlaybackTheora::stop() { } playing = false; time = 0; -}; +} bool VideoStreamPlaybackTheora::is_playing() const { return playing; -}; +} void VideoStreamPlaybackTheora::set_paused(bool p_paused) { paused = p_paused; -}; +} bool VideoStreamPlaybackTheora::is_paused() const { return paused; -}; +} void VideoStreamPlaybackTheora::set_loop(bool p_enable) { } bool VideoStreamPlaybackTheora::has_loop() const { return false; -}; +} -float VideoStreamPlaybackTheora::get_length() const { +double VideoStreamPlaybackTheora::get_length() const { return 0; -}; +} String VideoStreamPlaybackTheora::get_stream_name() const { return ""; -}; +} int VideoStreamPlaybackTheora::get_loop_count() const { return 0; -}; +} -float VideoStreamPlaybackTheora::get_playback_position() const { +double VideoStreamPlaybackTheora::get_playback_position() const { return get_time(); -}; +} -void VideoStreamPlaybackTheora::seek(float p_time) { +void VideoStreamPlaybackTheora::seek(double p_time) { WARN_PRINT_ONCE("Seeking in Theora videos is not implemented yet (it's only supported for GDExtension-provided video streams)."); } @@ -650,15 +657,14 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() { thread_sem = Semaphore::create(); #endif -}; +} VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() { #ifdef THEORA_USE_THREAD_STREAMING - memdelete(thread_sem); #endif clear(); -}; +} void VideoStreamTheora::_bind_methods() { ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamTheora::set_file); diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 00d799dc24..3efb653651 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -64,7 +64,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { int buffer_data(); int queue_page(ogg_page *page); void video_write(); - float get_time() const; + double get_time() const; bool theora_eos = false; bool vorbis_eos = false; @@ -136,19 +136,19 @@ public: virtual void set_loop(bool p_enable) override; virtual bool has_loop() const override; - virtual float get_length() const override; + virtual double get_length() const override; virtual String get_stream_name() const; virtual int get_loop_count() const; - virtual float get_playback_position() const override; - virtual void seek(float p_time) override; + virtual double get_playback_position() const override; + virtual void seek(double p_time) override; void set_file(const String &p_file); virtual Ref<Texture2D> get_texture() const override; - virtual void update(float p_delta) override; + virtual void update(double p_delta) override; virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) override; virtual int get_channels() const override; diff --git a/modules/tinyexr/config.py b/modules/tinyexr/config.py index 53b8f2f2e3..eb565b85b9 100644 --- a/modules/tinyexr/config.py +++ b/modules/tinyexr/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return env["tools"] + return env.editor_build def configure(env): diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 8315eea614..792103cd31 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -74,7 +74,7 @@ int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram if (beat_length_frames >= 0) { /** * Length determined by beat length - * This code is commented out because, in practice, it is prefered that the fade + * This code is commented out because, in practice, it is preferred that the fade * is done by the transitioner and this stream just goes on until it ends while fading out. * * End fade implementation is left here for reference in case at some point this feature @@ -153,8 +153,11 @@ int AudioStreamPlaybackOggVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p return -1; } - ERR_FAIL_COND_V_MSG((err = vorbis_synthesis(&block, packet)), 0, "Error during vorbis synthesis " + itos(err)); - ERR_FAIL_COND_V_MSG((err = vorbis_synthesis_blockin(&dsp_state, &block)), 0, "Error during vorbis block processing " + itos(err)); + err = vorbis_synthesis(&block, packet); + ERR_FAIL_COND_V_MSG(err != 0, 0, "Error during vorbis synthesis " + itos(err)); + + err = vorbis_synthesis_blockin(&dsp_state, &block); + ERR_FAIL_COND_V_MSG(err != 0, 0, "Error during vorbis block processing " + itos(err)); have_packets_left = !packet->e_o_s; } @@ -223,7 +226,7 @@ bool AudioStreamPlaybackOggVorbis::_alloc_vorbis() { return true; } -void AudioStreamPlaybackOggVorbis::start(float p_from_pos) { +void AudioStreamPlaybackOggVorbis::start(double p_from_pos) { ERR_FAIL_COND(!ready); loop_fade_remaining = FADE_SIZE; active = true; @@ -244,15 +247,15 @@ int AudioStreamPlaybackOggVorbis::get_loop_count() const { return loops; } -float AudioStreamPlaybackOggVorbis::get_playback_position() const { - return float(frames_mixed) / vorbis_data->get_sampling_rate(); +double AudioStreamPlaybackOggVorbis::get_playback_position() const { + return double(frames_mixed) / (double)vorbis_data->get_sampling_rate(); } void AudioStreamPlaybackOggVorbis::tag_used_streams() { vorbis_stream->tag_used(get_playback_position()); } -void AudioStreamPlaybackOggVorbis::seek(float p_time) { +void AudioStreamPlaybackOggVorbis::seek(double p_time) { ERR_FAIL_COND(!ready); ERR_FAIL_COND(vorbis_stream.is_null()); if (!active) { @@ -290,11 +293,15 @@ void AudioStreamPlaybackOggVorbis::seek(float p_time) { headers_remaining = 3; } if (!headers_remaining) { - ERR_FAIL_COND_MSG((err = vorbis_synthesis(&block, packet)), "Error during vorbis synthesis " + itos(err)); - ERR_FAIL_COND_MSG((err = vorbis_synthesis_blockin(&dsp_state, &block)), "Error during vorbis block processing " + itos(err)); + err = vorbis_synthesis(&block, packet); + ERR_FAIL_COND_MSG(err != 0, "Error during vorbis synthesis " + itos(err)); + + err = vorbis_synthesis_blockin(&dsp_state, &block); + ERR_FAIL_COND_MSG(err != 0, "Error during vorbis block processing " + itos(err)); int samples_out = vorbis_synthesis_pcmout(&dsp_state, nullptr); - ERR_FAIL_COND_MSG((err = vorbis_synthesis_read(&dsp_state, samples_out)), "Error during vorbis read updating " + itos(err)); + err = vorbis_synthesis_read(&dsp_state, samples_out); + ERR_FAIL_COND_MSG(err != 0, "Error during vorbis read updating " + itos(err)); samples_in_page += samples_out; @@ -341,12 +348,16 @@ void AudioStreamPlaybackOggVorbis::seek(float p_time) { headers_remaining = 3; } if (!headers_remaining) { - ERR_FAIL_COND_MSG((err = vorbis_synthesis(&block, packet)), "Error during vorbis synthesis " + itos(err)); - ERR_FAIL_COND_MSG((err = vorbis_synthesis_blockin(&dsp_state, &block)), "Error during vorbis block processing " + itos(err)); + err = vorbis_synthesis(&block, packet); + ERR_FAIL_COND_MSG(err != 0, "Error during vorbis synthesis " + itos(err)); + + err = vorbis_synthesis_blockin(&dsp_state, &block); + ERR_FAIL_COND_MSG(err != 0, "Error during vorbis block processing " + itos(err)); int samples_out = vorbis_synthesis_pcmout(&dsp_state, nullptr); int read_samples = samples_to_burn > samples_out ? samples_out : samples_to_burn; - ERR_FAIL_COND_MSG((err = vorbis_synthesis_read(&dsp_state, samples_out)), "Error during vorbis read updating " + itos(err)); + err = vorbis_synthesis_read(&dsp_state, samples_out); + ERR_FAIL_COND_MSG(err != 0, "Error during vorbis read updating " + itos(err)); samples_to_burn -= read_samples; if (samples_to_burn <= 0) { @@ -462,15 +473,15 @@ bool AudioStreamOggVorbis::has_loop() const { return loop; } -void AudioStreamOggVorbis::set_loop_offset(float p_seconds) { +void AudioStreamOggVorbis::set_loop_offset(double p_seconds) { loop_offset = p_seconds; } -float AudioStreamOggVorbis::get_loop_offset() const { +double AudioStreamOggVorbis::get_loop_offset() const { return loop_offset; } -float AudioStreamOggVorbis::get_length() const { +double AudioStreamOggVorbis::get_length() const { ERR_FAIL_COND_V(packet_sequence.is_null(), 0); return packet_sequence->get_length(); } diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index 0350e1f761..3aa99971be 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -83,14 +83,14 @@ protected: virtual float get_stream_sampling_rate() override; public: - virtual void start(float p_from_pos = 0.0) override; + virtual void start(double p_from_pos = 0.0) override; virtual void stop() override; virtual bool is_playing() const override; virtual int get_loop_count() const override; //times it looped - virtual float get_playback_position() const override; - virtual void seek(float p_time) override; + virtual double get_playback_position() const override; + virtual void seek(double p_time) override; virtual void tag_used_streams() override; @@ -127,8 +127,8 @@ public: void set_loop(bool p_enable); virtual bool has_loop() const override; - void set_loop_offset(float p_seconds); - float get_loop_offset() const; + void set_loop_offset(double p_seconds); + double get_loop_offset() const; void set_bpm(double p_bpm); virtual double get_bpm() const override; @@ -145,7 +145,7 @@ public: void set_packet_sequence(Ref<OggPacketSequence> p_packet_sequence); Ref<OggPacketSequence> get_packet_sequence() const; - virtual float get_length() const override; //if supported, otherwise return 0 + virtual double get_length() const override; //if supported, otherwise return 0 virtual bool is_monophonic() const override; diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index bf5f7206b8..a491c3d3fb 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -110,15 +110,18 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str size_t packet_count = 0; bool done = false; while (!done) { - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); + err = ogg_sync_check(&sync_state); + ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); while (ogg_sync_pageout(&sync_state, &page) != 1) { if (cursor >= len) { done = true; break; } - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); + err = ogg_sync_check(&sync_state); + ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE); - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); + err = ogg_sync_check(&sync_state); + ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); ERR_FAIL_COND_V(cursor > len, Ref<AudioStreamOggVorbis>()); size_t copy_size = len - cursor; if (copy_size > OGG_SYNC_BUFFER_SIZE) { @@ -127,12 +130,14 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str memcpy(sync_buf, &file_data[cursor], copy_size); ogg_sync_wrote(&sync_state, copy_size); cursor += copy_size; - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); + err = ogg_sync_check(&sync_state); + ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); } if (done) { break; } - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); + err = ogg_sync_check(&sync_state); + ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); // Have a page now. if (!initialized_stream) { @@ -142,7 +147,8 @@ Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const Str initialized_stream = true; } ogg_stream_pagein(&stream_state, &page); - ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Ref<AudioStreamOggVorbis>(), "Ogg stream error " + itos(err)); + err = ogg_stream_check(&stream_state); + ERR_FAIL_COND_V_MSG(err != 0, Ref<AudioStreamOggVorbis>(), "Ogg stream error " + itos(err)); int desync_iters = 0; Vector<Vector<uint8_t>> packet_data; diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub index 890fb71592..3f834471e5 100644 --- a/modules/websocket/SCsub +++ b/modules/websocket/SCsub @@ -41,7 +41,7 @@ elif env["builtin_wslay"]: module_obj = [] env_ws.add_source_files(module_obj, "*.cpp") -if env["tools"]: +if env.editor_build: env_ws.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h index a37a789cbe..0292de68ad 100644 --- a/modules/websocket/remote_debugger_peer_websocket.h +++ b/modules/websocket/remote_debugger_peer_websocket.h @@ -51,6 +51,7 @@ public: static RemoteDebuggerPeer *create(const String &p_uri); Error connect_to_host(const String &p_uri); + bool is_peer_connected() override; int get_max_message_size() const override; bool has_message() override; diff --git a/modules/xatlas_unwrap/config.py b/modules/xatlas_unwrap/config.py index 2e73c51626..ecc61c2d7e 100644 --- a/modules/xatlas_unwrap/config.py +++ b/modules/xatlas_unwrap/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return env["tools"] and platform not in ["android", "ios"] + return env.editor_build and platform not in ["android", "ios"] def configure(env): |