diff options
680 files changed, 38410 insertions, 8390 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index de0037d5e8..9f2449546e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -227,6 +227,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - More information in the [progress report](https://godotengine.org/article/improvements-shaders-visual-shaders-godot-4). - [Add Billboard mode to visual shaders.](https://github.com/godotengine/godot/pull/49157) - [The constants `PI`, `TAU` and `E` are now available in the shader language.](https://github.com/godotengine/godot/pull/48837) +- Uniform hints to control textures (`repeat_enabled`, `repeat_disabled`, `filter_linear`, `filter_nearest`, `hint_screen_texture`, etc.). #### Miscellaneous @@ -401,6 +402,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - [Removed support for 16× MSAA due to driver bugs and low performance.](https://github.com/godotengine/godot/pull/49063) - For high-quality offline rendering, using supersampling together with 8× MSAA is a better option anyway. +#### Shaders + +- Removed `SCREEN_TEXTURE` and `DEPTH_TEXTURE` in favor of uniform hints `hint_screen_texture` and `hint_depth_texture`. + ### Fixed #### Core diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 7fe45657bc..8a966dcb05 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -141,6 +141,11 @@ Comment: AMD FidelityFX Super Resolution Copyright: 2021, Advanced Micro Devices, Inc. License: Expat +Files: ./thirdparty/astcenc/ +Comment: Arm ASTC Encoder +Copyright: 2011-2023, Arm Limited +License: Apache-2.0 + Files: ./thirdparty/basis_universal/ Comment: Basis Universal Copyright: 2022, Binomial LLC. diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index de27b6d5ac..db3191334a 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1069,23 +1069,6 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p return ret; } -Vector<String> ProjectSettings::get_optimizer_presets() const { - List<PropertyInfo> pi; - ProjectSettings::get_singleton()->get_property_list(&pi); - Vector<String> names; - - for (const PropertyInfo &E : pi) { - if (!E.name.begins_with("optimizer_presets/")) { - continue; - } - names.push_back(E.name.get_slicec('/', 1)); - } - - names.sort(); - - return names; -} - void ProjectSettings::_add_property_info_bind(const Dictionary &p_info) { ERR_FAIL_COND(!p_info.has("name")); ERR_FAIL_COND(!p_info.has("type")); @@ -1249,12 +1232,9 @@ ProjectSettings::ProjectSettings() { singleton = this; GLOBAL_DEF_BASIC("application/config/name", ""); - GLOBAL_DEF_BASIC("application/config/name_localized", Dictionary()); - custom_prop_info["application/config/name_localized"] = PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING); - GLOBAL_DEF_BASIC("application/config/description", ""); - custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT); - GLOBAL_DEF_BASIC("application/run/main_scene", ""); - custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT), ""); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"), ""); GLOBAL_DEF("application/run/disable_stdout", false); GLOBAL_DEF("application/run/disable_stderr", false); GLOBAL_DEF_RST("application/config/use_hidden_project_data_directory", true); @@ -1266,22 +1246,15 @@ ProjectSettings::ProjectSettings() { // - Have a 16:9 aspect ratio, // - Have both dimensions divisible by 8 to better play along with video recording, // - Be displayable correctly in windowed mode on a 1366×768 display (tested on Windows 10 with default settings). - GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1152); - custom_prop_info["display/window/size/viewport_width"] = PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution - - GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648); - custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 1152); // 8K resolution + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 648); // 8K resolution - GLOBAL_DEF_BASIC("display/window/size/mode", 0); - custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), 0); // Keep the enum values in sync with the `DisplayServer::SCREEN_` enum. - GLOBAL_DEF_BASIC("display/window/size/initial_screen", -2); - String screen_hints = "Primary Monitor:-2"; // Note: Main Window Monitor:-1 is not used for the main window, skip it. - for (int i = 0; i < 64; i++) { - screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i); - } - custom_prop_info["display/window/size/initial_screen"] = PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_ENUM, screen_hints); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_position_type", PROPERTY_HINT_ENUM, "Absolute,Primary Screen Center,Other Screen Center"), 1); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::VECTOR2I, "display/window/size/initial_position"), Vector2i()); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), 0); GLOBAL_DEF_BASIC("display/window/size/resizable", true); GLOBAL_DEF_BASIC("display/window/size/borderless", false); @@ -1290,20 +1263,15 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("display/window/size/extend_to_title", false); GLOBAL_DEF("display/window/size/no_focus", false); - GLOBAL_DEF("display/window/size/window_width_override", 0); - custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution - GLOBAL_DEF("display/window/size/window_height_override", 0); - custom_prop_info["display/window/size/window_height_override"] = PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution + GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution + GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true); GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false); - GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres"); - custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"); - GLOBAL_DEF_RST("audio/general/2d_panning_strength", 0.5f); - custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"); - GLOBAL_DEF_RST("audio/general/3d_panning_strength", 0.5f); - custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"), "res://default_bus_layout.tres"); + GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f); + GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f); PackedStringArray extensions; extensions.push_back("gd"); @@ -1314,11 +1282,9 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("editor/run/main_run_args", ""); - GLOBAL_DEF("editor/script/search_in_file_extensions", extensions); - custom_prop_info["editor/script/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"); + GLOBAL_DEF(PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"), extensions); - GLOBAL_DEF("editor/script/templates_search_path", "res://script_templates"); - custom_prop_info["editor/script/templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR); + GLOBAL_DEF(PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR), "res://script_templates"); _add_builtin_input_map(); @@ -1330,21 +1296,13 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("physics/2d/run_on_separate_thread", false); GLOBAL_DEF("physics/3d/run_on_separate_thread", false); - GLOBAL_DEF("debug/settings/profiler/max_functions", 16384); - custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"); - - GLOBAL_DEF("compression/formats/zstd/long_distance_matching", Compression::zstd_long_distance_matching); - custom_prop_info["compression/formats/zstd/long_distance_matching"] = PropertyInfo(Variant::BOOL, "compression/formats/zstd/long_distance_matching"); - GLOBAL_DEF("compression/formats/zstd/compression_level", Compression::zstd_level); - custom_prop_info["compression/formats/zstd/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1"); - GLOBAL_DEF("compression/formats/zstd/window_log_size", Compression::zstd_window_log_size); - custom_prop_info["compression/formats/zstd/window_log_size"] = PropertyInfo(Variant::INT, "compression/formats/zstd/window_log_size", PROPERTY_HINT_RANGE, "10,30,1"); - - GLOBAL_DEF("compression/formats/zlib/compression_level", Compression::zlib_level); - custom_prop_info["compression/formats/zlib/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"); + GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"), 16384); - GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level); - custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"); + GLOBAL_DEF(PropertyInfo(Variant::BOOL, "compression/formats/zstd/long_distance_matching"), Compression::zstd_long_distance_matching); + GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1"), Compression::zstd_level); + GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/zstd/window_log_size", PROPERTY_HINT_RANGE, "10,30,1"), Compression::zstd_window_log_size); + GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"), Compression::zlib_level); + GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"), Compression::gzip_level); GLOBAL_DEF("debug/settings/crash_handler/message", String("Please include this when reporting the bug to the project developer.")); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 29c495c46b..d1704a7c31 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -178,8 +178,6 @@ public: const HashMap<StringName, PropertyInfo> &get_custom_property_info() const; uint64_t get_last_saved_time() { return last_save_time; } - Vector<String> get_optimizer_presets() const; - List<String> get_input_presets() const { return input_presets; } Variant get_setting_with_override(const StringName &p_name) const; diff --git a/core/core_bind.cpp b/core/core_bind.cpp index ab433bd8f1..96e1da9dde 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -322,8 +322,12 @@ String OS::get_environment(const String &p_var) const { return ::OS::get_singleton()->get_environment(p_var); } -bool OS::set_environment(const String &p_var, const String &p_value) const { - return ::OS::get_singleton()->set_environment(p_var, p_value); +void OS::set_environment(const String &p_var, const String &p_value) const { + ::OS::get_singleton()->set_environment(p_var, p_value); +} + +void OS::unset_environment(const String &p_var) const { + ::OS::get_singleton()->unset_environment(p_var); } String OS::get_name() const { @@ -548,9 +552,10 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("is_process_running", "pid"), &OS::is_process_running); ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id); + ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment); ClassDB::bind_method(D_METHOD("get_environment", "variable"), &OS::get_environment); ClassDB::bind_method(D_METHOD("set_environment", "variable", "value"), &OS::set_environment); - ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment); + ClassDB::bind_method(D_METHOD("unset_environment", "variable"), &OS::unset_environment); ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name); ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name); diff --git a/core/core_bind.h b/core/core_bind.h index 7ef346d1c4..c0c87fd009 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -162,7 +162,8 @@ public: bool has_environment(const String &p_var) const; String get_environment(const String &p_var) const; - bool set_environment(const String &p_var, const String &p_value) const; + void set_environment(const String &p_var, const String &p_value) const; + void unset_environment(const String &p_var) const; String get_name() const; String get_distribution_name() const; diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp index 8af1573bff..32725b76c1 100644 --- a/core/debugger/script_debugger.cpp +++ b/core/debugger/script_debugger.cpp @@ -73,10 +73,6 @@ bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const return breakpoints[p_line].has(p_source); } -bool ScriptDebugger::is_breakpoint_line(int p_line) const { - return breakpoints.has(p_line); -} - String ScriptDebugger::breakpoint_find_source(const String &p_source) const { return p_source; } diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h index c7aa90027b..edce089179 100644 --- a/core/debugger/script_debugger.h +++ b/core/debugger/script_debugger.h @@ -64,7 +64,6 @@ public: void insert_breakpoint(int p_line, const StringName &p_source); void remove_breakpoint(int p_line, const StringName &p_source); bool is_breakpoint(int p_line, const StringName &p_source) const; - bool is_breakpoint_line(int p_line) const; void clear_breakpoints(); const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; } diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp index ddfee3fc5d..8376c0aaf8 100644 --- a/core/error/error_macros.cpp +++ b/core/error/error_macros.cpp @@ -118,11 +118,11 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool p_editor_notify, bool p_fatal) { String fstr(p_fatal ? "FATAL: " : ""); String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ")."); - _err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message); + _err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, ERR_HANDLER_ERROR); } void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify, bool p_fatal) { - _err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_fatal); + _err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal); } void _err_flush_stdout() { diff --git a/core/error/error_macros.h b/core/error/error_macros.h index 63a2d22416..65804b7796 100644 --- a/core/error/error_macros.h +++ b/core/error/error_macros.h @@ -189,12 +189,12 @@ void _err_flush_stdout(); * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, the application crashes. */ -#define CRASH_BAD_INDEX(m_index, m_size) \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ - _err_flush_stdout(); \ - GENERATE_TRAP(); \ - } else \ +#define CRASH_BAD_INDEX(m_index, m_size) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \ + _err_flush_stdout(); \ + GENERATE_TRAP(); \ + } else \ ((void)0) /** @@ -204,12 +204,12 @@ void _err_flush_stdout(); * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, prints `m_msg` and the application crashes. */ -#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ - _err_flush_stdout(); \ - GENERATE_TRAP(); \ - } else \ +#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \ + _err_flush_stdout(); \ + GENERATE_TRAP(); \ + } else \ ((void)0) // Unsigned integer index out of bounds error macros. @@ -292,12 +292,12 @@ void _err_flush_stdout(); * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, the application crashes. */ -#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ - _err_flush_stdout(); \ - GENERATE_TRAP(); \ - } else \ +#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \ + _err_flush_stdout(); \ + GENERATE_TRAP(); \ + } else \ ((void)0) /** @@ -307,12 +307,12 @@ void _err_flush_stdout(); * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, prints `m_msg` and the application crashes. */ -#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ - _err_flush_stdout(); \ - GENERATE_TRAP(); \ - } else \ +#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \ + _err_flush_stdout(); \ + GENERATE_TRAP(); \ + } else \ ((void)0) // Null reference error macros. diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 312064a36c..7be14b741d 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -458,6 +458,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { // Global enums and constants. Array constants; HashMap<String, List<Pair<String, int64_t>>> enum_list; + HashMap<String, bool> enum_is_bitfield; for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { int64_t value = CoreConstants::get_global_constant_value(i); @@ -466,6 +467,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { bool bitfield = CoreConstants::is_global_constant_bitfield(i); if (!enum_name.is_empty()) { enum_list[enum_name].push_back(Pair<String, int64_t>(name, value)); + enum_is_bitfield[enum_name] = bitfield; } else { Dictionary d; d["name"] = name; @@ -481,6 +483,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { for (const KeyValue<String, List<Pair<String, int64_t>>> &E : enum_list) { Dictionary d1; d1["name"] = E.key; + d1["is_bitfield"] = enum_is_bitfield[E.key]; Array values; for (const Pair<String, int64_t> &F : E.value) { Dictionary d2; diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index bd4fa61bd5..a9063c8b27 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -31,8 +31,11 @@ #include "gdextension_interface.h" #include "core/config/engine.h" +#include "core/io/file_access.h" +#include "core/io/xml_parser.h" #include "core/object/class_db.h" #include "core/object/script_language_extension.h" +#include "core/object/worker_thread_pool.h" #include "core/os/memory.h" #include "core/variant/variant.h" #include "core/version.h" @@ -678,6 +681,59 @@ static const char32_t *gdextension_string_operator_index_const(GDExtensionConstS return &self->ptr()[p_index]; } +static void gdextension_string_operator_plus_eq_string(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b) { + String *self = (String *)p_self; + const String *b = (const String *)p_b; + *self += *b; +} + +static void gdextension_string_operator_plus_eq_char(GDExtensionStringPtr p_self, char32_t p_b) { + String *self = (String *)p_self; + *self += p_b; +} + +static void gdextension_string_operator_plus_eq_cstr(GDExtensionStringPtr p_self, const char *p_b) { + String *self = (String *)p_self; + *self += p_b; +} + +static void gdextension_string_operator_plus_eq_wcstr(GDExtensionStringPtr p_self, const wchar_t *p_b) { + String *self = (String *)p_self; + *self += p_b; +} + +static void gdextension_string_operator_plus_eq_c32str(GDExtensionStringPtr p_self, const char32_t *p_b) { + String *self = (String *)p_self; + *self += p_b; +} + +static GDExtensionInt gdextension_xml_parser_open_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) { + XMLParser *xml = (XMLParser *)p_instance; + return (GDExtensionInt)xml->_open_buffer(p_buffer, p_size); +} + +static void gdextension_file_access_store_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length) { + FileAccess *fa = (FileAccess *)p_instance; + fa->store_buffer(p_src, p_length); +} + +static uint64_t gdextension_file_access_get_buffer(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length) { + const FileAccess *fa = (FileAccess *)p_instance; + return fa->get_buffer(p_dst, p_length); +} + +static int64_t gdextension_worker_thread_pool_add_native_group_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) { + WorkerThreadPool *p = (WorkerThreadPool *)p_instance; + const String *description = (const String *)p_description; + return (int64_t)p->add_native_group_task(p_func, p_userdata, p_elements, p_tasks, static_cast<bool>(p_high_priority), *description); +} + +static int64_t gdextension_worker_thread_pool_add_native_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) { + WorkerThreadPool *p = (WorkerThreadPool *)p_instance; + const String *description = (const String *)p_description; + return (int64_t)p->add_native_task(p_func, p_userdata, static_cast<bool>(p_high_priority), *description); +} + /* Packed array functions */ static uint8_t *gdextension_packed_byte_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) { @@ -1025,6 +1081,25 @@ void gdextension_setup_interface(GDExtensionInterface *p_interface) { gde_interface.string_to_wide_chars = gdextension_string_to_wide_chars; gde_interface.string_operator_index = gdextension_string_operator_index; gde_interface.string_operator_index_const = gdextension_string_operator_index_const; + gde_interface.string_operator_plus_eq_string = gdextension_string_operator_plus_eq_string; + gde_interface.string_operator_plus_eq_char = gdextension_string_operator_plus_eq_char; + gde_interface.string_operator_plus_eq_cstr = gdextension_string_operator_plus_eq_cstr; + gde_interface.string_operator_plus_eq_wcstr = gdextension_string_operator_plus_eq_wcstr; + gde_interface.string_operator_plus_eq_c32str = gdextension_string_operator_plus_eq_c32str; + + /* XMLParser extra utilities */ + + gde_interface.xml_parser_open_buffer = gdextension_xml_parser_open_buffer; + + /* FileAccess extra utilities */ + + gde_interface.file_access_store_buffer = gdextension_file_access_store_buffer; + gde_interface.file_access_get_buffer = gdextension_file_access_get_buffer; + + /* WorkerThreadPool extra utilities */ + + gde_interface.worker_thread_pool_add_native_group_task = gdextension_worker_thread_pool_add_native_group_task; + gde_interface.worker_thread_pool_add_native_task = gdextension_worker_thread_pool_add_native_task; /* Packed array functions */ diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index 190298ee8a..6e5dee8265 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -503,6 +503,26 @@ typedef struct { char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index); const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index); + void (*string_operator_plus_eq_string)(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b); + void (*string_operator_plus_eq_char)(GDExtensionStringPtr p_self, char32_t p_b); + void (*string_operator_plus_eq_cstr)(GDExtensionStringPtr p_self, const char *p_b); + void (*string_operator_plus_eq_wcstr)(GDExtensionStringPtr p_self, const wchar_t *p_b); + void (*string_operator_plus_eq_c32str)(GDExtensionStringPtr p_self, const char32_t *p_b); + + /* XMLParser extra utilities */ + + GDExtensionInt (*xml_parser_open_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size); + + /* FileAccess extra utilities */ + + void (*file_access_store_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length); + uint64_t (*file_access_get_buffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length); + + /* WorkerThreadPool extra utilities */ + + int64_t (*worker_thread_pool_add_native_group_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description); + int64_t (*worker_thread_pool_add_native_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description); + /* Packed array functions */ uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray diff --git a/core/input/input_builders.py b/core/input/input_builders.py index a7729c9af2..76e199e0ff 100644 --- a/core/input/input_builders.py +++ b/core/input/input_builders.py @@ -45,7 +45,7 @@ def make_default_controller_mappings(target, source, env): platform_mappings[current_platform][guid] = line platform_variables = { - "Linux": "#if X11_ENABLED", + "Linux": "#if LINUXBSD_ENABLED", "Windows": "#ifdef WINDOWS_ENABLED", "Mac OS X": "#ifdef MACOS_ENABLED", "Android": "#if defined(__ANDROID__)", diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 77d1bdcc5c..cacbcb28a4 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -292,7 +292,7 @@ real_t FileAccess::get_real() const { Variant FileAccess::get_var(bool p_allow_objects) const { uint32_t len = get_32(); - Vector<uint8_t> buff = _get_buffer(len); + Vector<uint8_t> buff = get_buffer(len); ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant()); const uint8_t *r = buff.ptr(); @@ -469,7 +469,7 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { return i; } -Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const { +Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const { Vector<uint8_t> data; ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0."); @@ -663,7 +663,7 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { } } -void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) { +void FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) { uint64_t len = p_buffer.size(); if (len == 0) { return; @@ -687,7 +687,7 @@ void FileAccess::store_var(const Variant &p_var, bool p_full_objects) { ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); store_32(len); - _store_buffer(buff); + store_buffer(buff); } Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) { @@ -829,7 +829,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float); ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double); ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real); - ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer); + ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector<uint8_t>(FileAccess::*)(int64_t) const) & FileAccess::get_buffer); ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line); ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false)); @@ -847,7 +847,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float); ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double); ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real); - ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer); + ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (void(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer); ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line); ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string); diff --git a/core/io/file_access.h b/core/io/file_access.h index 3116ed521f..3e51ba11ed 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -127,7 +127,7 @@ public: Variant get_var(bool p_allow_objects = false) const; virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes - Vector<uint8_t> _get_buffer(int64_t p_length) const; + Vector<uint8_t> get_buffer(int64_t p_length) const; virtual String get_line() const; virtual String get_token() const; virtual Vector<String> get_csv_line(const String &p_delim = ",") const; @@ -162,7 +162,7 @@ public: virtual String get_pascal_string(); virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes - void _store_buffer(const Vector<uint8_t> &p_buffer); + void store_buffer(const Vector<uint8_t> &p_buffer); void store_var(const Variant &p_var, bool p_full_objects = false); diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 17fb199811..c6452f1033 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -135,10 +135,6 @@ void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) { loader.erase(p_loader); } -const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() { - return loader; -} - void ImageLoader::cleanup() { while (loader.size()) { remove_image_format_loader(loader[0]); diff --git a/core/io/image_loader.h b/core/io/image_loader.h index 1473f24186..ac51f13376 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -98,8 +98,6 @@ public: static void add_image_format_loader(Ref<ImageFormatLoader> p_loader); static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader); - static const Vector<Ref<ImageFormatLoader>> &get_image_format_loaders(); - static void cleanup(); }; diff --git a/core/io/json.cpp b/core/io/json.cpp index ca29534c35..448e39b2c3 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -30,6 +30,7 @@ #include "json.h" +#include "core/config/engine.h" #include "core/string/print_string.h" const char *JSON::tk_name[TK_MAX] = { @@ -506,6 +507,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, void JSON::set_data(const Variant &p_data) { data = p_data; + text.clear(); } Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { @@ -539,14 +541,21 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st return err; } -Error JSON::parse(const String &p_json_string) { +Error JSON::parse(const String &p_json_string, bool p_keep_text) { Error err = _parse_string(p_json_string, data, err_str, err_line); if (err == Error::OK) { err_line = 0; } + if (p_keep_text) { + text = p_json_string; + } return err; } +String JSON::get_parsed_text() const { + return text; +} + String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { Ref<JSON> jason; jason.instantiate(); @@ -565,10 +574,11 @@ Variant JSON::parse_string(const String &p_json_string) { void JSON::_bind_methods() { ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false)); ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string); - ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); + ClassDB::bind_method(D_METHOD("parse", "json_text", "keep_text"), &JSON::parse, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data); ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data); + ClassDB::bind_method(D_METHOD("get_parsed_text"), &JSON::get_parsed_text); ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line); ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message); @@ -592,13 +602,20 @@ Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String Ref<JSON> json; json.instantiate(); - Error err = json->parse(FileAccess::get_file_as_string(p_path)); + Error err = json->parse(FileAccess::get_file_as_string(p_path), Engine::get_singleton()->is_editor_hint()); if (err != OK) { - if (r_error) { - *r_error = err; + String err_text = "Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message(); + + if (Engine::get_singleton()->is_editor_hint()) { + // If running on editor, still allow opening the JSON so the code editor can edit it. + WARN_PRINT(err_text); + } else { + if (r_error) { + *r_error = err; + } + ERR_PRINT(err_text); + return Ref<Resource>(); } - ERR_PRINT("Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message()); - return Ref<Resource>(); } if (r_error) { @@ -628,7 +645,7 @@ Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const Strin Ref<JSON> json = p_resource; ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER); - String source = JSON::stringify(json->get_data(), "\t", false, true); + String source = json->get_parsed_text().is_empty() ? JSON::stringify(json->get_data(), "\t", false, true) : json->get_parsed_text(); Error err; Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); diff --git a/core/io/json.h b/core/io/json.h index d66a4e24a3..a21cc542fd 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -36,8 +36,8 @@ #include "core/io/resource_saver.h" #include "core/variant/variant.h" -class JSON : public RefCounted { - GDCLASS(JSON, RefCounted); +class JSON : public Resource { + GDCLASS(JSON, Resource); enum TokenType { TK_CURLY_BRACKET_OPEN, @@ -65,6 +65,7 @@ class JSON : public RefCounted { Variant value; }; + String text; Variant data; String err_str; int err_line = 0; @@ -83,7 +84,9 @@ protected: static void _bind_methods(); public: - Error parse(const String &p_json_string); + Error parse(const String &p_json_string, bool p_keep_text = false); + String get_parsed_text() const; + static String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); static Variant parse_string(const String &p_json_string); diff --git a/core/io/marshalls.h b/core/io/marshalls.h index 5e760c7565..6f015ac386 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -44,7 +44,7 @@ typedef uint32_t uintr_t; #endif /** - * Miscellaneous helpers for marshalling data types, and encoding + * Miscellaneous helpers for marshaling data types, and encoding * in an endian independent way */ diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 2d6f09725f..6d3575b9fa 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -385,10 +385,6 @@ void Resource::set_as_translation_remapped(bool p_remapped) { ResourceCache::lock.unlock(); } -bool Resource::is_translation_remapped() const { - return remapped_list.in_list(); -} - #ifdef TOOLS_ENABLED //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored void Resource::set_id_for_path(const String &p_path, const String &p_id) { @@ -481,9 +477,6 @@ void ResourceCache::clear() { resources.clear(); } -void ResourceCache::reload_externals() { -} - bool ResourceCache::has(const String &p_path) { lock.lock(); diff --git a/core/io/resource.h b/core/io/resource.h index 22ce5cef43..5135664f36 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -136,7 +136,6 @@ public: #endif void set_as_translation_remapped(bool p_remapped); - bool is_translation_remapped() const; virtual RID get_rid() const; // some resources may offer conversion to RID @@ -164,7 +163,6 @@ class ResourceCache { friend void register_core_types(); public: - static void reload_externals(); static bool has(const String &p_path); static Ref<Resource> get_ref(const String &p_path); static void get_cached_resources(List<Ref<Resource>> *p_resources); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 45e1301930..c0463de427 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -91,7 +91,8 @@ enum { // Version 2: added 64 bits support for float and int. // Version 3: changed nodepath encoding. // Version 4: new string ID for ext/subresources, breaks forward compat. - FORMAT_VERSION = 4, + // Version 5: Ability to store script class in the header. + FORMAT_VERSION = 5, FORMAT_VERSION_CAN_RENAME_DEPS = 1, FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3, }; @@ -661,10 +662,6 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { return OK; //never reach anyway } -void ResourceLoaderBinary::set_local_path(const String &p_local_path) { - res_path = p_local_path; -} - Ref<Resource> ResourceLoaderBinary::get_resource() { return resource; } @@ -1013,6 +1010,10 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p uid = ResourceUID::INVALID_ID; } + if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) { + script_class = get_unicode_string(); + } + for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) { f->get_32(); //skip a few reserved fields } @@ -1117,6 +1118,57 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) { return get_unicode_string(); } +String ResourceLoaderBinary::recognize_script_class(Ref<FileAccess> p_f) { + error = OK; + + f = p_f; + uint8_t header[4]; + f->get_buffer(header, 4); + if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') { + // Compressed. + Ref<FileAccessCompressed> fac; + fac.instantiate(); + error = fac->open_after_magic(f); + if (error != OK) { + f.unref(); + return ""; + } + f = fac; + + } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') { + // Not normal. + error = ERR_FILE_UNRECOGNIZED; + f.unref(); + return ""; + } + + bool big_endian = f->get_32(); + f->get_32(); // use_real64 + + f->set_big_endian(big_endian != 0); //read big endian if saved as big endian + + uint32_t ver_major = f->get_32(); + f->get_32(); // ver_minor + uint32_t ver_fmt = f->get_32(); + + if (ver_fmt > FORMAT_VERSION || ver_major > VERSION_MAJOR) { + f.unref(); + return ""; + } + + get_unicode_string(); // type + + f->get_64(); // Metadata offset + uint32_t flags = f->get_32(); + f->get_64(); // UID + + if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) { + return get_unicode_string(); + } else { + return String(); + } +} + Ref<Resource> ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; @@ -1299,6 +1351,9 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons fw->store_32(flags); fw->store_64(uid_data); + if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) { + save_ustring(fw, get_ustring(f)); + } for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) { fw->store_32(0); // reserved @@ -1420,6 +1475,18 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const return ClassDB::get_compatibility_remapped_class(r); } +String ResourceFormatLoaderBinary::get_resource_script_class(const String &p_path) const { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { + return ""; //could not read + } + + ResourceLoaderBinary loader; + loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); + loader.res_path = loader.local_path; + return loader.recognize_script_class(f); +} + ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_path) const { String ext = p_path.get_extension().to_lower(); if (!ClassDB::is_resource_extension(ext)) { @@ -2037,15 +2104,31 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re save_unicode_string(f, _resource_get_class(p_resource)); f->store_64(0); //offset to import metadata + + String script_class; { uint32_t format_flags = FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS; #ifdef REAL_T_IS_DOUBLE format_flags |= FORMAT_FLAG_REAL_T_IS_DOUBLE; #endif + if (!p_resource->is_class("PackedScene")) { + Ref<Script> s = p_resource->get_script(); + if (s.is_valid()) { + script_class = s->get_global_name(); + if (!script_class.is_empty()) { + format_flags |= ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS; + } + } + } + f->store_32(format_flags); } ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p_path, true); f->store_64(uid); + if (!script_class.is_empty()) { + save_unicode_string(f, script_class); + } + for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) { f->store_32(0); // reserved } @@ -2298,6 +2381,10 @@ Error ResourceFormatSaverBinaryInstance::set_uid(const String &p_path, ResourceU fw->store_32(flags); fw->store_64(p_uid); + if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) { + save_ustring(fw, get_ustring(f)); + } + //rest of file uint8_t b = f->get_8(); while (!f->eof_reached()) { diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 2e8988005f..add7cdf297 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -65,6 +65,7 @@ class ResourceLoaderBinary { bool using_named_scene_ids = false; bool using_uids = false; + String script_class; bool use_sub_threads = false; float *progress = nullptr; Vector<ExtResource> external_resources; @@ -92,7 +93,6 @@ class ResourceLoaderBinary { HashMap<String, Ref<Resource>> dependency_cache; public: - void set_local_path(const String &p_local_path); Ref<Resource> get_resource(); Error load(); void set_translation_remapped(bool p_remapped); @@ -100,6 +100,7 @@ public: void set_remaps(const HashMap<String, String> &p_remaps) { remaps = p_remaps; } void open(Ref<FileAccess> p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false); String recognize(Ref<FileAccess> p_f); + String recognize_script_class(Ref<FileAccess> p_f); void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types); void get_classes_used(Ref<FileAccess> p_f, HashSet<StringName> *p_classes); @@ -113,6 +114,7 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; + virtual String get_resource_script_class(const String &p_path) const; virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); virtual ResourceUID::ID get_resource_uid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); @@ -165,6 +167,7 @@ public: FORMAT_FLAG_NAMED_SCENE_IDS = 1, FORMAT_FLAG_UIDS = 2, FORMAT_FLAG_REAL_T_IS_DOUBLE = 4, + FORMAT_FLAG_HAS_SCRIPT_CLASS = 8, // Amount of reserved 32-bit fields in resource header RESERVED_FIELDS = 11 diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 946c31cf0d..7447119ab7 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -99,6 +99,12 @@ String ResourceFormatLoader::get_resource_type(const String &p_path) const { return ret; } +String ResourceFormatLoader::get_resource_script_class(const String &p_path) const { + String ret; + GDVIRTUAL_CALL(_get_resource_script_class, p_path, ret); + return ret; +} + ResourceUID::ID ResourceFormatLoader::get_resource_uid(const String &p_path) const { int64_t uid = ResourceUID::INVALID_ID; GDVIRTUAL_CALL(_get_resource_uid, p_path, uid); @@ -184,6 +190,7 @@ void ResourceFormatLoader::_bind_methods() { GDVIRTUAL_BIND(_recognize_path, "path", "type"); GDVIRTUAL_BIND(_handles_type, "type"); GDVIRTUAL_BIND(_get_resource_type, "path"); + GDVIRTUAL_BIND(_get_resource_script_class, "path"); GDVIRTUAL_BIND(_get_resource_uid, "path"); GDVIRTUAL_BIND(_get_dependencies, "path", "add_types"); GDVIRTUAL_BIND(_rename_dependencies, "path", "renames"); @@ -764,6 +771,19 @@ String ResourceLoader::get_resource_type(const String &p_path) { return ""; } +String ResourceLoader::get_resource_script_class(const String &p_path) { + String local_path = _validate_local_path(p_path); + + for (int i = 0; i < loader_count; i++) { + String result = loader[i]->get_resource_script_class(local_path); + if (!result.is_empty()) { + return result; + } + } + + return ""; +} + ResourceUID::ID ResourceLoader::get_resource_uid(const String &p_path) { String local_path = _validate_local_path(p_path); @@ -1011,13 +1031,6 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { return true; } -void ResourceLoader::remove_custom_resource_format_loader(String script_path) { - Ref<ResourceFormatLoader> custom_loader = _find_custom_resource_format_loader(script_path); - if (custom_loader.is_valid()) { - remove_resource_format_loader(custom_loader); - } -} - void ResourceLoader::set_create_missing_resources_if_class_unavailable(bool p_enable) { create_missing_resources_if_class_unavailable = p_enable; } diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 41ba0dc6e6..eb8155e046 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -54,6 +54,7 @@ protected: GDVIRTUAL2RC(bool, _recognize_path, String, StringName) GDVIRTUAL1RC(bool, _handles_type, StringName) GDVIRTUAL1RC(String, _get_resource_type, String) + GDVIRTUAL1RC(String, _get_resource_script_class, String) GDVIRTUAL1RC(ResourceUID::ID, _get_resource_uid, String) GDVIRTUAL2RC(Vector<String>, _get_dependencies, String, bool) GDVIRTUAL1RC(Vector<String>, _get_classes_used, String) @@ -71,6 +72,7 @@ public: virtual bool handles_type(const String &p_type) const; virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); virtual String get_resource_type(const String &p_path) const; + virtual String get_resource_script_class(const String &p_path) const; virtual ResourceUID::ID get_resource_uid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map); @@ -175,6 +177,7 @@ public: static void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader); static void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); static String get_resource_type(const String &p_path); + static String get_resource_script_class(const String &p_path); static ResourceUID::ID get_resource_uid(const String &p_path); static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); static Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map); @@ -225,7 +228,6 @@ public: static ResourceLoaderImport import; static bool add_custom_resource_format_loader(String script_path); - static void remove_custom_resource_format_loader(String script_path); static void add_custom_loaders(); static void remove_custom_loaders(); diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 9809b9a48f..b8201cc6b9 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -250,13 +250,6 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { return true; } -void ResourceSaver::remove_custom_resource_format_saver(String script_path) { - Ref<ResourceFormatSaver> custom_saver = _find_custom_resource_format_saver(script_path); - if (custom_saver.is_valid()) { - remove_resource_format_saver(custom_saver); - } -} - void ResourceSaver::add_custom_savers() { // Custom resource savers exploits global class names diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 2043947963..9e88b2086b 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -101,7 +101,6 @@ public: static void set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback); static bool add_custom_resource_format_saver(String script_path); - static void remove_custom_resource_format_saver(String script_path); static void add_custom_savers(); static void remove_custom_savers(); }; diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index 09836419be..5c0a017bfc 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -354,10 +354,10 @@ void XMLParser::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node_offset"), &XMLParser::get_node_offset); ClassDB::bind_method(D_METHOD("get_attribute_count"), &XMLParser::get_attribute_count); ClassDB::bind_method(D_METHOD("get_attribute_name", "idx"), &XMLParser::get_attribute_name); - ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), (String(XMLParser::*)(int) const) & XMLParser::get_attribute_value); + ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), &XMLParser::get_attribute_value); ClassDB::bind_method(D_METHOD("has_attribute", "name"), &XMLParser::has_attribute); - ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), (String(XMLParser::*)(const String &) const) & XMLParser::get_attribute_value); - ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_attribute_value_safe); + ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), &XMLParser::get_named_attribute_value); + ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_named_attribute_value_safe); ClassDB::bind_method(D_METHOD("is_empty"), &XMLParser::is_empty); ClassDB::bind_method(D_METHOD("get_current_line"), &XMLParser::get_current_line); ClassDB::bind_method(D_METHOD("skip_section"), &XMLParser::skip_section); @@ -422,7 +422,7 @@ bool XMLParser::has_attribute(const String &p_name) const { return false; } -String XMLParser::get_attribute_value(const String &p_name) const { +String XMLParser::get_named_attribute_value(const String &p_name) const { int idx = -1; for (int i = 0; i < attributes.size(); i++) { if (attributes[i].name == p_name) { @@ -436,7 +436,7 @@ String XMLParser::get_attribute_value(const String &p_name) const { return attributes[idx].value; } -String XMLParser::get_attribute_value_safe(const String &p_name) const { +String XMLParser::get_named_attribute_value_safe(const String &p_name) const { int idx = -1; for (int i = 0; i < attributes.size(); i++) { if (attributes[i].name == p_name) { diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index b4ae5c93b6..b96478c7a5 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -109,8 +109,8 @@ public: String get_attribute_name(int p_idx) const; String get_attribute_value(int p_idx) const; bool has_attribute(const String &p_name) const; - String get_attribute_value(const String &p_name) const; - String get_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist + String get_named_attribute_value(const String &p_name) const; + String get_named_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist bool is_empty() const; int get_current_line() const; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index a54804c5dc..646bdea758 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -106,11 +106,11 @@ void AStar3D::remove_point(int64_t p_id) { bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't remove point. Point with id: %d doesn't exist.", p_id)); - for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) { Segment s(p_id, (*it.key)); segments.erase(s); - (*it.value)->neighbours.remove(p->id); + (*it.value)->neighbors.remove(p->id); (*it.value)->unlinked_neighbours.remove(p->id); } @@ -118,7 +118,7 @@ void AStar3D::remove_point(int64_t p_id) { Segment s(p_id, (*it.key)); segments.erase(s); - (*it.value)->neighbours.remove(p->id); + (*it.value)->neighbors.remove(p->id); (*it.value)->unlinked_neighbours.remove(p->id); } @@ -138,10 +138,10 @@ void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional bool to_exists = points.lookup(p_with_id, b); ERR_FAIL_COND_MSG(!to_exists, vformat("Can't connect points. Point with id: %d doesn't exist.", p_with_id)); - a->neighbours.set(b->id, b); + a->neighbors.set(b->id, b); if (bidirectional) { - b->neighbours.set(a->id, a); + b->neighbors.set(a->id, a); } else { b->unlinked_neighbours.set(a->id, a); } @@ -155,7 +155,7 @@ void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional if (element) { s.direction |= element->direction; if (s.direction == Segment::BIDIRECTIONAL) { - // Both are neighbours of each other now + // Both are neighbors of each other now a->unlinked_neighbours.remove(b->id); b->unlinked_neighbours.remove(a->id); } @@ -183,9 +183,9 @@ void AStar3D::disconnect_points(int64_t p_id, int64_t p_with_id, bool bidirectio // Erase the directions to be removed s.direction = (element->direction & ~remove_direction); - a->neighbours.remove(b->id); + a->neighbors.remove(b->id); if (bidirectional) { - b->neighbours.remove(a->id); + b->neighbors.remove(a->id); if (element->direction != Segment::BIDIRECTIONAL) { a->unlinked_neighbours.remove(b->id); b->unlinked_neighbours.remove(a->id); @@ -226,7 +226,7 @@ Vector<int64_t> AStar3D::get_point_connections(int64_t p_id) { Vector<int64_t> point_list; - for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) { point_list.push_back((*it.key)); } @@ -346,8 +346,8 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { open_list.remove_at(open_list.size() - 1); p->closed_pass = pass; // Mark the point as closed - for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { - Point *e = *(it.value); // The neighbour point + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) { + Point *e = *(it.value); // The neighbor point if (!e->enabled || e->closed_pass == pass) { continue; @@ -794,7 +794,7 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { bool found_route = false; - Vector<AStar3D::Point *> open_list; + LocalVector<AStar3D::Point *> open_list; SortArray<AStar3D::Point *, AStar3D::SortPoints> sorter; begin_point->g_score = 0; @@ -802,19 +802,19 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { open_list.push_back(begin_point); while (!open_list.is_empty()) { - AStar3D::Point *p = open_list[0]; // The currently processed point + AStar3D::Point *p = open_list[0]; // The currently processed point. if (p == end_point) { found_route = true; break; } - sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list + sorter.pop_heap(0, open_list.size(), open_list.ptr()); // Remove the current point from the open list. open_list.remove_at(open_list.size() - 1); - p->closed_pass = astar.pass; // Mark the point as closed + p->closed_pass = astar.pass; // Mark the point as closed. - for (OAHashMap<int64_t, AStar3D::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { - AStar3D::Point *e = *(it.value); // The neighbour point + for (OAHashMap<int64_t, AStar3D::Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) { + AStar3D::Point *e = *(it.value); // The neighbor point. if (!e->enabled || e->closed_pass == astar.pass) { continue; @@ -837,9 +837,9 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { e->f_score = e->g_score + _estimate_cost(e->id, end_point->id); if (new_point) { // The position of the new points is already known. - sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw()); + sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr()); } else { - sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw()); + sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptr()); } } } diff --git a/core/math/a_star.h b/core/math/a_star.h index a475e4f2fc..fc4bb09f03 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -52,7 +52,7 @@ class AStar3D : public RefCounted { real_t weight_scale = 0; bool enabled = false; - OAHashMap<int64_t, Point *> neighbours = 4u; + OAHashMap<int64_t, Point *> neighbors = 4u; OAHashMap<int64_t, Point *> unlinked_neighbours = 4u; // Used for pathfinding. diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp index 30d50073d7..677e609763 100644 --- a/core/math/a_star_grid_2d.cpp +++ b/core/math/a_star_grid_2d.cpp @@ -401,7 +401,7 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) { List<Point *> nbors; _get_nbors(p, nbors); for (List<Point *>::Element *E = nbors.front(); E; E = E->next()) { - Point *e = E->get(); // The neighbour point. + Point *e = E->get(); // The neighbor point. real_t weight_scale = 1.0; if (jumping_enabled) { diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 39e383fb49..234a4ddb79 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -36,23 +36,6 @@ #define cofac(row1, col1, row2, col2) \ (rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1]) -void Basis::from_z(const Vector3 &p_z) { - if (Math::abs(p_z.z) > (real_t)Math_SQRT12) { - // choose p in y-z plane - real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2]; - real_t k = 1.0f / Math::sqrt(a); - rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k); - rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]); - } else { - // choose p in x-y plane - real_t a = p_z.x * p_z.x + p_z.y * p_z.y; - real_t k = 1.0f / Math::sqrt(a); - rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0); - rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k); - } - rows[2] = p_z; -} - void Basis::invert() { real_t co[3] = { cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1) @@ -271,14 +254,6 @@ float Basis::get_uniform_scale() const { return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; } -void Basis::make_scale_uniform() { - float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; - for (int i = 0; i < 3; i++) { - rows[i].normalize(); - rows[i] *= l; - } -} - Basis Basis::scaled_local(const Vector3 &p_scale) const { return (*this) * Basis::from_scale(p_scale); } diff --git a/core/math/basis.h b/core/math/basis.h index b3197dbc84..bbc1d40469 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -56,8 +56,6 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ real_t determinant() const; - void from_z(const Vector3 &p_z); - void rotate(const Vector3 &p_axis, real_t p_angle); Basis rotated(const Vector3 &p_axis, real_t p_angle) const; @@ -101,8 +99,6 @@ struct _NO_DISCARD_ Basis { void scale_orthogonal(const Vector3 &p_scale); Basis scaled_orthogonal(const Vector3 &p_scale) const; - - void make_scale_uniform(); float get_uniform_scale() const; Vector3 get_scale() const; diff --git a/core/math/bvh.h b/core/math/bvh.h index 9de704834b..357d483375 100644 --- a/core/math/bvh.h +++ b/core/math/bvh.h @@ -444,9 +444,7 @@ private: params.result_array = nullptr; params.subindex_array = nullptr; - for (unsigned int n = 0; n < changed_items.size(); n++) { - const BVHHandle &h = changed_items[n]; - + for (const BVHHandle &h : changed_items) { // use the expanded aabb for pairing const BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb; BVHABB_CLASS abb; @@ -465,9 +463,7 @@ private: params.result_count_overall = 0; // might not be needed tree.cull_aabb(params, false); - for (unsigned int i = 0; i < tree._cull_hits.size(); i++) { - uint32_t ref_id = tree._cull_hits[i]; - + for (const uint32_t ref_id : tree._cull_hits) { // don't collide against ourself if (ref_id == changed_item_ref_id) { continue; diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h index 32b011bd3b..fb0207e0bd 100644 --- a/core/math/bvh_abb.h +++ b/core/math/bvh_abb.h @@ -87,7 +87,7 @@ struct BVH_ABB { return -neg_max - min; } - POINT calculate_centre() const { + POINT calculate_center() const { return POINT((calculate_size() * 0.5) + min); } diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc index 180bbfb511..875abedb70 100644 --- a/core/math/bvh_split.inc +++ b/core/math/bvh_split.inc @@ -25,7 +25,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u return; } - POINT centre = full_bound.calculate_centre(); + POINT center = full_bound.calculate_center(); POINT size = full_bound.calculate_size(); int order[POINT::AXIS_COUNT]; @@ -43,7 +43,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u for (int a = 0; a < num_a; a++) { uint32_t ind = group_a[a]; - if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) { + if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) { // add to b group_b[num_b++] = ind; @@ -75,7 +75,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u for (int a = 0; a < num_a; a++) { uint32_t ind = group_a[a]; - if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) { + if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) { count++; } } @@ -100,7 +100,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u for (int a = 0; a < num_a; a++) { uint32_t ind = group_a[a]; - if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) { + if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) { // add to b group_b[num_b++] = ind; diff --git a/core/math/color.cpp b/core/math/color.cpp index 5bae8d25d6..3e5fa7b402 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -194,7 +194,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) { a = p_alpha; if (p_s == 0.0f) { - // Achromatic (grey) + // Achromatic (gray) r = g = b = p_v; return; } diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 8ca38d571a..55923e0133 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -313,20 +313,20 @@ public: //remove simplex and continue simplex_list.erase(simplex->SE); - for (uint32_t k = 0; k < simplex->grid_positions.size(); k++) { - Vector3i p = simplex->grid_positions[k].pos; - acceleration_grid[p.x][p.y][p.z].erase(simplex->grid_positions[k].E); + for (const GridPos &gp : simplex->grid_positions) { + Vector3i p = gp.pos; + acceleration_grid[p.x][p.y][p.z].erase(gp.E); } memdelete(simplex); } E = N; } - for (uint32_t j = 0; j < triangles.size(); j++) { - if (triangles[j].bad) { + for (const Triangle &triangle : triangles) { + if (triangle.bad) { continue; } - Simplex *new_simplex = memnew(Simplex(triangles[j].triangle[0], triangles[j].triangle[1], triangles[j].triangle[2], i)); + Simplex *new_simplex = memnew(Simplex(triangle.triangle[0], triangle.triangle[1], triangle.triangle[2], i)); circum_sphere_compute(points, new_simplex); new_simplex->SE = simplex_list.push_back(new_simplex); { diff --git a/core/math/expression.cpp b/core/math/expression.cpp index da52bb9465..d1ec987d56 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -434,14 +434,13 @@ Error Expression::_get_token(Token &r_token) { } return OK; - } else if (is_ascii_char(cchar) || is_underscore(cchar)) { - String id; - bool first = true; + } else if (is_unicode_identifier_start(cchar)) { + String id = String::chr(cchar); + cchar = GET_CHAR(); - while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) { + while (is_unicode_identifier_continue(cchar)) { id += String::chr(cchar); cchar = GET_CHAR(); - first = false; } str_ofs--; //go back one diff --git a/core/math/face3.cpp b/core/math/face3.cpp index e53bbf872b..1dff0ee4a6 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -120,36 +120,6 @@ bool Face3::is_degenerate() const { return (normal.length_squared() < (real_t)CMP_EPSILON2); } -Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const { - int over = 0, under = 0; - - Plane plane = get_plane(p_clock_dir); - - for (int i = 0; i < 3; i++) { - const Vector3 &v = p_face.vertex[i]; - - if (plane.has_point(v)) { //coplanar, don't bother - continue; - } - - if (plane.is_point_over(v)) { - over++; - } else { - under++; - } - } - - if (over > 0 && under == 0) { - return SIDE_OVER; - } else if (under > 0 && over == 0) { - return SIDE_UNDER; - } else if (under == 0 && over == 0) { - return SIDE_COPLANAR; - } else { - return SIDE_SPANNING; - } -} - Vector3 Face3::get_random_point_inside() const { real_t a = Math::random(0.0, 1.0); real_t b = Math::random(0.0, 1.0); @@ -164,20 +134,10 @@ Plane Face3::get_plane(ClockDirection p_dir) const { return Plane(vertex[0], vertex[1], vertex[2], p_dir); } -Vector3 Face3::get_median_point() const { - return (vertex[0] + vertex[1] + vertex[2]) / 3.0f; -} - real_t Face3::get_area() const { return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length() * 0.5f; } -ClockDirection Face3::get_clock_dir() const { - Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]); - //printf("normal is %g,%g,%g x %g,%g,%g- wtfu is %g\n",tofloat(normal.x),tofloat(normal.y),tofloat(normal.z),tofloat(vertex[0].x),tofloat(vertex[0].y),tofloat(vertex[0].z),tofloat( normal.dot( vertex[0] ) ) ); - return (normal.dot(vertex[0]) >= 0) ? CLOCKWISE : COUNTERCLOCKWISE; -} - bool Face3::intersects_aabb(const AABB &p_aabb) const { /** TEST PLANE **/ if (!p_aabb.intersects_plane(get_plane())) { diff --git a/core/math/face3.h b/core/math/face3.h index 3d87de03dc..3dd47d0226 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -57,19 +57,14 @@ struct _NO_DISCARD_ Face3 { Plane get_plane(ClockDirection p_dir = CLOCKWISE) const; Vector3 get_random_point_inside() const; - Side get_side_of(const Face3 &p_face, ClockDirection p_clock_dir = CLOCKWISE) const; - bool is_degenerate() const; real_t get_area() const; - Vector3 get_median_point() const; Vector3 get_closest_point_to(const Vector3 &p_point) const; bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const; bool intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const; - ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity - void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp index a0b76d31cb..74cb92539a 100644 --- a/core/math/geometry_2d.cpp +++ b/core/math/geometry_2d.cpp @@ -320,41 +320,6 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly return polypaths; } -Vector<Point2i> Geometry2D::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) { - Vector<stbrp_node> nodes; - nodes.resize(p_atlas_size.width); - - stbrp_context context; - stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width); - - Vector<stbrp_rect> rects; - rects.resize(p_sizes.size()); - - for (int i = 0; i < p_sizes.size(); i++) { - rects.write[i].id = 0; - rects.write[i].w = p_sizes[i].width; - rects.write[i].h = p_sizes[i].height; - rects.write[i].x = 0; - rects.write[i].y = 0; - rects.write[i].was_packed = 0; - } - - int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size()); - if (res == 0) { //pack failed - return Vector<Point2i>(); - } - - Vector<Point2i> ret; - ret.resize(p_sizes.size()); - - for (int i = 0; i < p_sizes.size(); i++) { - Point2i r(rects[i].x, rects[i].y); - ret.write[i] = r; - } - - return ret; -} - Vector<Vector3i> Geometry2D::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) { Vector<stbrp_node> nodes; nodes.resize(p_atlas_size.width); diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index b55aecf85e..0e5702e0af 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -464,7 +464,6 @@ public: static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon); static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size); - static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size); static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size); private: diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index c04fe7320d..4786110054 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -141,21 +141,19 @@ real_t Geometry3D::get_closest_distance_between_segments(const Vector3 &p_p0, co void Geometry3D::MeshData::optimize_vertices() { HashMap<int, int> vtx_remap; - for (uint32_t i = 0; i < faces.size(); i++) { - for (uint32_t j = 0; j < faces[i].indices.size(); j++) { - int idx = faces[i].indices[j]; - if (!vtx_remap.has(idx)) { + for (MeshData::Face &face : faces) { + for (int &index : face.indices) { + if (!vtx_remap.has(index)) { int ni = vtx_remap.size(); - vtx_remap[idx] = ni; + vtx_remap[index] = ni; } - - faces[i].indices[j] = vtx_remap[idx]; + index = vtx_remap[index]; } } - for (uint32_t i = 0; i < edges.size(); i++) { - int a = edges[i].vertex_a; - int b = edges[i].vertex_b; + for (MeshData::Edge edge : edges) { + int a = edge.vertex_a; + int b = edge.vertex_b; if (!vtx_remap.has(a)) { int ni = vtx_remap.size(); @@ -166,8 +164,8 @@ void Geometry3D::MeshData::optimize_vertices() { vtx_remap[b] = ni; } - edges[i].vertex_a = vtx_remap[a]; - edges[i].vertex_b = vtx_remap[b]; + edge.vertex_a = vtx_remap[a]; + edge.vertex_b = vtx_remap[b]; } LocalVector<Vector3> new_vertices; @@ -198,149 +196,6 @@ struct _FaceClassify { _FaceClassify() {} }; -static bool _connect_faces(_FaceClassify *p_faces, int len, int p_group) { - // Connect faces, error will occur if an edge is shared between more than 2 faces. - // Clear connections. - - bool error = false; - - for (int i = 0; i < len; i++) { - for (int j = 0; j < 3; j++) { - p_faces[i].links[j].clear(); - } - } - - for (int i = 0; i < len; i++) { - if (p_faces[i].group != p_group) { - continue; - } - for (int j = i + 1; j < len; j++) { - if (p_faces[j].group != p_group) { - continue; - } - - for (int k = 0; k < 3; k++) { - Vector3 vi1 = p_faces[i].face.vertex[k]; - Vector3 vi2 = p_faces[i].face.vertex[(k + 1) % 3]; - - for (int l = 0; l < 3; l++) { - Vector3 vj2 = p_faces[j].face.vertex[l]; - Vector3 vj1 = p_faces[j].face.vertex[(l + 1) % 3]; - - if (vi1.distance_to(vj1) < 0.00001f && - vi2.distance_to(vj2) < 0.00001f) { - if (p_faces[i].links[k].face != -1) { - ERR_PRINT("already linked\n"); - error = true; - break; - } - if (p_faces[j].links[l].face != -1) { - ERR_PRINT("already linked\n"); - error = true; - break; - } - - p_faces[i].links[k].face = j; - p_faces[i].links[k].edge = l; - p_faces[j].links[l].face = i; - p_faces[j].links[l].edge = k; - } - } - if (error) { - break; - } - } - if (error) { - break; - } - } - if (error) { - break; - } - } - - for (int i = 0; i < len; i++) { - p_faces[i].valid = true; - for (int j = 0; j < 3; j++) { - if (p_faces[i].links[j].face == -1) { - p_faces[i].valid = false; - } - } - } - return error; -} - -static bool _group_face(_FaceClassify *p_faces, int len, int p_index, int p_group) { - if (p_faces[p_index].group >= 0) { - return false; - } - - p_faces[p_index].group = p_group; - - for (int i = 0; i < 3; i++) { - ERR_FAIL_INDEX_V(p_faces[p_index].links[i].face, len, true); - _group_face(p_faces, len, p_faces[p_index].links[i].face, p_group); - } - - return true; -} - -Vector<Vector<Face3>> Geometry3D::separate_objects(Vector<Face3> p_array) { - Vector<Vector<Face3>> objects; - - int len = p_array.size(); - - const Face3 *arrayptr = p_array.ptr(); - - Vector<_FaceClassify> fc; - - fc.resize(len); - - _FaceClassify *_fcptr = fc.ptrw(); - - for (int i = 0; i < len; i++) { - _fcptr[i].face = arrayptr[i]; - } - - bool error = _connect_faces(_fcptr, len, -1); - - ERR_FAIL_COND_V_MSG(error, Vector<Vector<Face3>>(), "Invalid geometry."); - - // Group connected faces in separate objects. - - int group = 0; - for (int i = 0; i < len; i++) { - if (!_fcptr[i].valid) { - continue; - } - if (_group_face(_fcptr, len, i, group)) { - group++; - } - } - - // Group connected faces in separate objects. - - for (int i = 0; i < len; i++) { - _fcptr[i].face = arrayptr[i]; - } - - if (group >= 0) { - objects.resize(group); - Vector<Face3> *group_faces = objects.ptrw(); - - for (int i = 0; i < len; i++) { - if (!_fcptr[i].valid) { - continue; - } - if (_fcptr[i].group >= 0 && _fcptr[i].group < group) { - group_faces[_fcptr[i].group].push_back(_fcptr[i].face); - } - } - } - - return objects; -} - /*** GEOMETRY WRAPPER ***/ enum _CellFlags { @@ -816,10 +671,10 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes MeshData::Face face; // Add face indices. - for (uint32_t j = 0; j < vertices.size(); j++) { + for (const Vector3 &vertex : vertices) { int idx = -1; for (uint32_t k = 0; k < mesh.vertices.size(); k++) { - if (mesh.vertices[k].distance_to(vertices[j]) < 0.001f) { + if (mesh.vertices[k].distance_to(vertex) < 0.001f) { idx = k; break; } @@ -827,7 +682,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes if (idx == -1) { idx = mesh.vertices.size(); - mesh.vertices.push_back(vertices[j]); + mesh.vertices.push_back(vertex); } face.indices.push_back(idx); diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h index 6759db5766..99c554fe05 100644 --- a/core/math/geometry_3d.h +++ b/core/math/geometry_3d.h @@ -532,8 +532,6 @@ public: return clipped; } - static Vector<Vector<Face3>> separate_objects(Vector<Face3> p_array); - // Create a "wrap" that encloses the given geometry. static Vector<Face3> wrap_geometry(Vector<Face3> p_array, real_t *p_error = nullptr); diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 6a7ee32230..910995d717 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -221,12 +221,6 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const { return t; } -Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { - Transform2D copy = *this; - copy.scale_basis(p_scale); - return copy; -} - Transform2D Transform2D::scaled(const Size2 &p_scale) const { // Equivalent to left multiplication Transform2D copy = *this; diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 2a0917c63f..4a17a9db37 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -85,7 +85,6 @@ struct _NO_DISCARD_ Transform2D { _FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; } _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; } - Transform2D basis_scaled(const Size2 &p_scale) const; Transform2D scaled(const Size2 &p_scale) const; Transform2D scaled_local(const Size2 &p_scale) const; Transform2D translated(const Vector2 &p_offset) const; diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 4b6921d38b..0da1b8c7ad 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -182,90 +182,6 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces, const Vector<int32_t> valid = true; } -Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const { - uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); - - enum { - TEST_AABB_BIT = 0, - VISIT_LEFT_BIT = 1, - VISIT_RIGHT_BIT = 2, - VISIT_DONE_BIT = 3, - VISITED_BIT_SHIFT = 29, - NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1, - VISITED_BIT_MASK = ~NODE_IDX_MASK, - - }; - - int n_count = 0; - Vector3 n; - - int level = 0; - - const Triangle *triangleptr = triangles.ptr(); - // const Vector3 *verticesr = vertices.ptr(); - const BVH *bvhptr = bvh.ptr(); - - int pos = bvh.size() - 1; - - stack[0] = pos; - while (true) { - uint32_t node = stack[level] & NODE_IDX_MASK; - const BVH &b = bvhptr[node]; - bool done = false; - - switch (stack[level] >> VISITED_BIT_SHIFT) { - case TEST_AABB_BIT: { - if (!b.aabb.intersects(p_aabb)) { - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - } else { - if (b.face_index >= 0) { - const Triangle &s = triangleptr[b.face_index]; - n += s.normal; - n_count++; - - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - - } else { - stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node; - } - } - continue; - } - case VISIT_LEFT_BIT: { - stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; - level++; - stack[level] = b.left | TEST_AABB_BIT; - continue; - } - case VISIT_RIGHT_BIT: { - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - level++; - stack[level] = b.right | TEST_AABB_BIT; - continue; - } - case VISIT_DONE_BIT: { - if (level == 0) { - done = true; - break; - } else { - level--; - } - continue; - } - } - - if (done) { - break; - } - } - - if (n_count > 0) { - n /= n_count; - } - - return n; -} - bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); @@ -468,118 +384,6 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V return inters; } -bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const { - uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); - - //p_fully_inside = true; - - enum { - TEST_AABB_BIT = 0, - VISIT_LEFT_BIT = 1, - VISIT_RIGHT_BIT = 2, - VISIT_DONE_BIT = 3, - VISITED_BIT_SHIFT = 29, - NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1, - VISITED_BIT_MASK = ~NODE_IDX_MASK, - - }; - - int level = 0; - - const Triangle *triangleptr = triangles.ptr(); - const Vector3 *vertexptr = vertices.ptr(); - const BVH *bvhptr = bvh.ptr(); - - int pos = bvh.size() - 1; - - stack[0] = pos; - while (true) { - uint32_t node = stack[level] & NODE_IDX_MASK; - const BVH &b = bvhptr[node]; - bool done = false; - - switch (stack[level] >> VISITED_BIT_SHIFT) { - case TEST_AABB_BIT: { - if (!b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count)) { - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - } else { - if (b.face_index >= 0) { - const Triangle &s = triangleptr[b.face_index]; - - for (int j = 0; j < 3; ++j) { - const Vector3 &point = vertexptr[s.indices[j]]; - const Vector3 &next_point = vertexptr[s.indices[(j + 1) % 3]]; - Vector3 res; - bool over = true; - for (int i = 0; i < p_plane_count; i++) { - const Plane &p = p_planes[i]; - - if (p.intersects_segment(point, next_point, &res)) { - bool inisde = true; - for (int k = 0; k < p_plane_count; k++) { - if (k == i) { - continue; - } - const Plane &pp = p_planes[k]; - if (pp.is_point_over(res)) { - inisde = false; - break; - } - } - if (inisde) { - return true; - } - } - - if (p.is_point_over(point)) { - over = false; - break; - } - } - if (over) { - return true; - } - } - - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - - } else { - stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node; - } - } - continue; - } - case VISIT_LEFT_BIT: { - stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; - level++; - stack[level] = b.left | TEST_AABB_BIT; - continue; - } - case VISIT_RIGHT_BIT: { - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - level++; - stack[level] = b.right | TEST_AABB_BIT; - continue; - } - case VISIT_DONE_BIT: { - if (level == 0) { - done = true; - break; - } else { - level--; - } - continue; - } - } - - if (done) { - break; - } - } - - return false; -} - bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 728fd600d5..24fc12dda9 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -84,9 +84,7 @@ public: bool is_valid() const; bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; - bool intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const; bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const; - Vector3 get_area_normal(const AABB &p_aabb) const; Vector<Face3> get_faces() const; const Vector<Triangle> &get_triangles() const { return triangles; } diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index c9cfbdd4cb..df5486512d 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -245,9 +245,12 @@ void ScriptServer::thread_exit() { } HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes; +HashMap<StringName, Vector<StringName>> ScriptServer::inheriters_cache; +bool ScriptServer::inheriters_cache_dirty = true; void ScriptServer::global_classes_clear() { global_classes.clear(); + inheriters_cache.clear(); } void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) { @@ -257,10 +260,47 @@ void ScriptServer::add_global_class(const StringName &p_class, const StringName g.path = p_path; g.base = p_base; global_classes[p_class] = g; + inheriters_cache_dirty = true; } void ScriptServer::remove_global_class(const StringName &p_class) { global_classes.erase(p_class); + inheriters_cache_dirty = true; +} + +void ScriptServer::get_inheriters_list(const StringName &p_base_type, List<StringName> *r_classes) { + if (inheriters_cache_dirty) { + inheriters_cache.clear(); + for (const KeyValue<StringName, GlobalScriptClass> &K : global_classes) { + if (!inheriters_cache.has(K.value.base)) { + inheriters_cache[K.value.base] = Vector<StringName>(); + } + inheriters_cache[K.value.base].push_back(K.key); + } + for (KeyValue<StringName, Vector<StringName>> &K : inheriters_cache) { + K.value.sort_custom<StringName::AlphCompare>(); + } + inheriters_cache_dirty = false; + } + + if (!inheriters_cache.has(p_base_type)) { + return; + } + + const Vector<StringName> &v = inheriters_cache[p_base_type]; + for (int i = 0; i < v.size(); i++) { + r_classes->push_back(v[i]); + } +} + +void ScriptServer::remove_global_class_by_path(const String &p_path) { + for (const KeyValue<StringName, GlobalScriptClass> &kv : global_classes) { + if (kv.value.path == p_path) { + global_classes.erase(kv.key); + inheriters_cache_dirty = true; + return; + } + } } bool ScriptServer::is_global_class(const StringName &p_class) { diff --git a/core/object/script_language.h b/core/object/script_language.h index ff678bcd25..f82b58439f 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -56,10 +56,12 @@ class ScriptServer { struct GlobalScriptClass { StringName language; String path; - String base; + StringName base; }; static HashMap<StringName, GlobalScriptClass> global_classes; + static HashMap<StringName, Vector<StringName>> inheriters_cache; + static bool inheriters_cache_dirty; public: static ScriptEditRequestFunction edit_request_func; @@ -80,12 +82,14 @@ public: static void global_classes_clear(); static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path); static void remove_global_class(const StringName &p_class); + static void remove_global_class_by_path(const String &p_path); static bool is_global_class(const StringName &p_class); static StringName get_global_class_language(const StringName &p_class); static String get_global_class_path(const String &p_class); static StringName get_global_class_base(const String &p_class); static StringName get_global_class_native_base(const String &p_class); static void get_global_class_list(List<StringName> *r_global_classes); + static void get_inheriters_list(const StringName &p_base_type, List<StringName> *r_classes); static void save_global_classes(); static void init_languages(); @@ -119,7 +123,7 @@ public: virtual bool can_instantiate() const = 0; virtual Ref<Script> get_base_script() const = 0; //for script inheritance - + virtual StringName get_global_name() const = 0; virtual bool inherits_script(const Ref<Script> &p_script) const = 0; virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 912f2218c4..8e162a1b0f 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -53,6 +53,7 @@ protected: public: EXBIND0RC(bool, can_instantiate) EXBIND0RC(Ref<Script>, get_base_script) + EXBIND0RC(StringName, get_global_name) EXBIND1RC(bool, inherits_script, const Ref<Script> &) EXBIND0RC(StringName, get_instance_base_type) diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index e84933eb69..077929351e 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -99,8 +99,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { } } - for (unsigned int i = 0; i < to_remove.size(); i++) { - List<Operation>::Element *E = to_remove[i]; + for (List<Operation>::Element *E : to_remove) { // Delete all object references E->get().delete_reference(); E->erase(); diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index fc907b2301..721c8d0a10 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -377,11 +377,11 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) { Group *group = *groupp; if (group->low_priority_native_tasks.size() > 0) { - for (uint32_t i = 0; i < group->low_priority_native_tasks.size(); i++) { - group->low_priority_native_tasks[i]->low_priority_thread->wait_to_finish(); - native_thread_allocator.free(group->low_priority_native_tasks[i]->low_priority_thread); + for (Task *task : group->low_priority_native_tasks) { + task->low_priority_thread->wait_to_finish(); + native_thread_allocator.free(task->low_priority_thread); task_mutex.lock(); - task_allocator.free(group->low_priority_native_tasks[i]); + task_allocator.free(task); task_mutex.unlock(); } @@ -449,8 +449,8 @@ void WorkerThreadPool::finish() { task_available_semaphore.post(); } - for (uint32_t i = 0; i < threads.size(); i++) { - threads[i].thread.wait_to_finish(); + for (ThreadData &data : threads) { + data.thread.wait_to_finish(); } threads.clear(); diff --git a/core/os/os.cpp b/core/os/os.cpp index c6fa8d307b..86469852e3 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -203,16 +203,26 @@ uint64_t OS::get_embedded_pck_offset() const { } // Helper function to ensure that a dir name/path will be valid on the OS -String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_dir_separator) const { +String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_paths) const { + String safe_dir_name = p_dir_name; Vector<String> invalid_chars = String(": * ? \" < > |").split(" "); - if (p_allow_dir_separator) { + if (p_allow_paths) { // Dir separators are allowed, but disallow ".." to avoid going up the filesystem invalid_chars.push_back(".."); + safe_dir_name = safe_dir_name.replace("\\", "/").strip_edges(); } else { invalid_chars.push_back("/"); + invalid_chars.push_back("\\"); + safe_dir_name = safe_dir_name.strip_edges(); + + // These directory names are invalid. + if (safe_dir_name == ".") { + safe_dir_name = "dot"; + } else if (safe_dir_name == "..") { + safe_dir_name = "twodots"; + } } - String safe_dir_name = p_dir_name.replace("\\", "/").strip_edges(); for (int i = 0; i < invalid_chars.size(); i++) { safe_dir_name = safe_dir_name.replace(invalid_chars[i], "-"); } diff --git a/core/os/os.h b/core/os/os.h index b80efa47b7..436a83eae3 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -167,7 +167,8 @@ public: virtual bool has_environment(const String &p_var) const = 0; virtual String get_environment(const String &p_var) const = 0; - virtual bool set_environment(const String &p_var, const String &p_value) const = 0; + virtual void set_environment(const String &p_var, const String &p_value) const = 0; + virtual void unset_environment(const String &p_var) const = 0; virtual String get_name() const = 0; virtual String get_distribution_name() const = 0; @@ -237,7 +238,7 @@ public: virtual uint64_t get_embedded_pck_offset() const; - String get_safe_dir_name(const String &p_dir_name, bool p_allow_dir_separator = false) const; + String get_safe_dir_name(const String &p_dir_name, bool p_allow_paths = false) const; virtual String get_godot_dir_name() const; virtual String get_data_path() const; diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h index 55761bb604..5311a94987 100644 --- a/core/templates/local_vector.h +++ b/core/templates/local_vector.h @@ -169,6 +169,70 @@ public: return data[p_index]; } + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return *elem_ptr; + } + _FORCE_INLINE_ T *operator->() const { return elem_ptr; } + _FORCE_INLINE_ Iterator &operator++() { + elem_ptr++; + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + elem_ptr--; + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; } + + Iterator(T *p_ptr) { elem_ptr = p_ptr; } + Iterator() {} + Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + T *elem_ptr = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return *elem_ptr; + } + _FORCE_INLINE_ const T *operator->() const { return elem_ptr; } + _FORCE_INLINE_ ConstIterator &operator++() { + elem_ptr++; + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + elem_ptr--; + return *this; + } + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; } + + ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; } + ConstIterator() {} + ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + const T *elem_ptr = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(data); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(data + size()); + } + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(ptr()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(ptr() + size()); + } + void insert(U p_pos, T p_val) { ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1); if (p_pos == count) { diff --git a/core/variant/variant.h b/core/variant/variant.h index fff59c43a6..b9294de77d 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -655,6 +655,7 @@ public: static bool has_indexing(Variant::Type p_type); static Variant::Type get_indexed_element_type(Variant::Type p_type); + static uint32_t get_indexed_element_usage(Variant::Type p_type); typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool *oob); typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool *oob); diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index b8d4495702..30fb5d0e9f 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -151,8 +151,8 @@ void unregister_named_setters_getters() { bool Variant::has_member(Variant::Type p_type, const StringName &p_member) { ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); - for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) { - if (variant_setters_getters_names[p_type][i] == p_member) { + for (const StringName &member : variant_setters_getters_names[p_type]) { + if (member == p_member) { return true; } } @@ -172,8 +172,8 @@ Variant::Type Variant::get_member_type(Variant::Type p_type, const StringName &p } void Variant::get_member_list(Variant::Type p_type, List<StringName> *r_members) { - for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) { - r_members->push_back(variant_setters_getters_names[p_type][i]); + for (const StringName &member : variant_setters_getters_names[p_type]) { + r_members->push_back(member); } } @@ -389,6 +389,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { v.write[index] = PtrToArg<m_elem_type>::convert(member); \ } \ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \ + static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \ }; @@ -460,6 +461,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { v.write[index] = PtrToArg<m_elem_type>::convert(member); \ } \ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \ + static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \ }; @@ -515,6 +517,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { v[index] = PtrToArg<m_elem_type>::convert(member); \ } \ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \ + static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \ }; @@ -564,6 +567,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { v m_accessor[index] = PtrToArg<m_elem_type>::convert(member); \ } \ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \ + static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \ }; @@ -613,6 +617,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { v.m_set(index, PtrToArg<m_elem_type>::convert(member)); \ } \ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \ + static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \ }; @@ -683,6 +688,7 @@ struct VariantIndexedSetGet_Array { v.set(index, PtrToArg<Variant>::convert(member)); } static Variant::Type get_index_type() { return Variant::NIL; } + static uint32_t get_index_usage() { return PROPERTY_USAGE_NIL_IS_VARIANT; } static uint64_t get_indexed_size(const Variant *base) { return 0; } }; @@ -768,6 +774,7 @@ struct VariantIndexedSetGet_String { } } static Variant::Type get_index_type() { return Variant::STRING; } + static uint32_t get_index_usage() { return PROPERTY_USAGE_DEFAULT; } static uint64_t get_indexed_size(const Variant *base) { return VariantInternal::get_string(base)->length(); } }; @@ -812,6 +819,7 @@ struct VariantIndexedSetGet_String { v[index] = PtrToArg<Variant>::convert(member); \ } \ static Variant::Type get_index_type() { return Variant::NIL; } \ + static uint32_t get_index_usage() { return PROPERTY_USAGE_DEFAULT; } \ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \ }; @@ -852,7 +860,8 @@ struct VariantIndexedSetterGetterInfo { uint64_t (*get_indexed_size)(const Variant *base) = nullptr; - Variant::Type index_type; + Variant::Type index_type = Variant::NIL; + uint32_t index_usage = PROPERTY_USAGE_DEFAULT; bool valid = false; }; @@ -872,6 +881,7 @@ static void register_indexed_member(Variant::Type p_type) { sgi.ptr_getter = T::ptr_get; sgi.index_type = T::get_index_type(); + sgi.index_usage = T::get_index_usage(); sgi.get_indexed_size = T::get_indexed_size; sgi.valid = true; @@ -920,6 +930,11 @@ Variant::Type Variant::get_indexed_element_type(Variant::Type p_type) { return variant_indexed_setters_getters[p_type].index_type; } +uint32_t Variant::get_indexed_element_usage(Variant::Type p_type) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, PROPERTY_USAGE_DEFAULT); + return variant_indexed_setters_getters[p_type].index_usage; +} + Variant::ValidatedIndexedSetter Variant::get_member_validated_indexed_setter(Variant::Type p_type) { ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr); return variant_indexed_setters_getters[p_type].validated_setter; @@ -1253,7 +1268,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { return _data._int > 0; } break; case FLOAT: { - r_iter = 0; + r_iter = 0.0; return _data._float > 0.0; } break; case VECTOR2: { @@ -1457,7 +1472,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { return true; } break; case FLOAT: { - int64_t idx = r_iter; + double idx = r_iter; idx++; if (idx >= _data._float) { return false; diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index 4da9e41ca8..c0e5d6ad07 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -53,7 +53,7 @@ <return type="void" /> <param index="0" name="button" type="Control" /> <description> - Removes the [param button] from the dialog. Does NOT free the [param button]. The [param button] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [param button] will no longer emit this dialog's [signal custom_action] or [signal cancelled] signals. + Removes the [param button] from the dialog. Does NOT free the [param button]. The [param button] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [param button] will no longer emit this dialog's [signal custom_action] or [signal canceled] signals. </description> </method> </methods> @@ -81,7 +81,7 @@ <member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" overrides="Window" default="true" /> </members> <signals> - <signal name="cancelled"> + <signal name="canceled"> <description> Emitted when the dialog is closed or the button created with [method add_cancel_button] is pressed. </description> diff --git a/doc/classes/AnimatableBody3D.xml b/doc/classes/AnimatableBody3D.xml index 2a08c4c8f1..0733780bf7 100644 --- a/doc/classes/AnimatableBody3D.xml +++ b/doc/classes/AnimatableBody3D.xml @@ -7,6 +7,7 @@ Animatable body for 3D physics. An animatable body can't be moved by external forces or contacts, but can be moved by script or animation to affect other bodies in its path. It is ideal for implementing moving objects in the environment, such as moving platforms or doors. When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml index e20fb71c7e..cd9c0cee98 100644 --- a/doc/classes/AnimatedSprite2D.xml +++ b/doc/classes/AnimatedSprite2D.xml @@ -7,7 +7,6 @@ [AnimatedSprite2D] is similar to the [Sprite2D] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel. After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor. To pause the current animation, set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time. - [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps. </description> <tutorials> <link title="2D Sprite animation">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link> diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index a33ec2f6dc..6e3345b675 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -49,6 +49,13 @@ When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node. </description> </method> + <method name="_is_parameter_read_only" qualifiers="virtual const"> + <return type="bool" /> + <param index="0" name="parameter" type="StringName" /> + <description> + When inheriting from [AnimationRootNode], implement this virtual method to return whether the [param parameter] is read-only. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. + </description> + </method> <method name="_process" qualifiers="virtual const"> <return type="float" /> <param index="0" name="time" type="float" /> diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml index 14abc34992..9e8193868c 100644 --- a/doc/classes/AnimationNodeOneShot.xml +++ b/doc/classes/AnimationNodeOneShot.xml @@ -28,6 +28,12 @@ </member> </members> <constants> + <constant name="ONE_SHOT_REQUEST_NONE" value="0" enum="OneShotRequest"> + </constant> + <constant name="ONE_SHOT_REQUEST_FIRE" value="1" enum="OneShotRequest"> + </constant> + <constant name="ONE_SHOT_REQUEST_ABORT" value="2" enum="OneShotRequest"> + </constant> <constant name="MIX_MODE_BLEND" value="0" enum="MixMode"> </constant> <constant name="MIX_MODE_ADD" value="1" enum="MixMode"> diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml index 8f53ef0dcf..17a946bb3e 100644 --- a/doc/classes/AnimationNodeStateMachinePlayback.xml +++ b/doc/classes/AnimationNodeStateMachinePlayback.xml @@ -38,6 +38,12 @@ Returns the playback position within the current animation state. </description> </method> + <method name="get_fading_from_node" qualifiers="const"> + <return type="StringName" /> + <description> + Returns the starting state of currently fading animation. + </description> + </method> <method name="get_travel_path" qualifiers="const"> <return type="PackedStringArray" /> <description> @@ -50,11 +56,19 @@ Returns [code]true[/code] if an animation is playing. </description> </method> + <method name="next"> + <return type="void" /> + <description> + If there is a next path by travel or auto advance, immediately transitions from the current state to the next state. + </description> + </method> <method name="start"> <return type="void" /> <param index="0" name="node" type="StringName" /> + <param index="1" name="reset" type="bool" default="true" /> <description> Starts playing the given animation. + If [param reset] is [code]true[/code], the animation is played from the beginning. </description> </method> <method name="stop"> @@ -66,8 +80,11 @@ <method name="travel"> <return type="void" /> <param index="0" name="to_node" type="StringName" /> + <param index="1" name="reset_on_teleport" type="bool" default="true" /> <description> Transitions from the current state to another one, following the shortest path. + If the path does not connect from the current state, the animation will play after the state teleports. + If [param reset_on_teleport] is [code]true[/code], the animation is played from the beginning when the travel cause a teleportation. </description> </method> </methods> diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 814b2d0052..eee25fad7c 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -28,6 +28,9 @@ <member name="priority" type="int" setter="set_priority" getter="get_priority" default="1"> Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member advance_mode] is set to [constant ADVANCE_MODE_AUTO]. </member> + <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true"> + If [code]true[/code], the destination animation is played back from the beginning when switched. + </member> <member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0"> The transition type. </member> diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml index f6e2fc5eb2..bca94a568a 100644 --- a/doc/classes/AnimationNodeTransition.xml +++ b/doc/classes/AnimationNodeTransition.xml @@ -12,6 +12,12 @@ <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> </tutorials> <methods> + <method name="find_input_caption" qualifiers="const"> + <return type="int" /> + <param index="0" name="caption" type="String" /> + <description> + </description> + </method> <method name="get_input_caption" qualifiers="const"> <return type="String" /> <param index="0" name="input" type="int" /> @@ -43,7 +49,7 @@ <member name="enabled_inputs" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0"> The number of enabled input ports for this node. </member> - <member name="from_start" type="bool" setter="set_from_start" getter="is_from_start" default="true"> + <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true"> If [code]true[/code], the destination animation is played back from the beginning when switched. </member> <member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve"> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index ca0cbf0ca1..304caeef43 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -208,9 +208,11 @@ </method> <method name="stop"> <return type="void" /> + <param index="0" name="keep_state" type="bool" default="false" /> <description> - Stops the currently playing animation. The animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code]. - See also [method pause]. + Stops the currently playing animation. The animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code]. See also [method pause]. + If [param keep_state] is [code]true[/code], the animation state is not updated visually. + [b]Note:[/b] The method / audio / animation playback tracks will not be processed by this method. </description> </method> </methods> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index a17a727d7e..49bc4ee6af 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -104,7 +104,7 @@ </member> <member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath("")"> The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code]. - If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be cancelled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView]. + If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be canceled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView]. </member> <member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root"> The root animation node of this [AnimationTree]. See [AnimationNode]. diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml index 8923ac8aae..d40bca99d8 100644 --- a/doc/classes/Area3D.xml +++ b/doc/classes/Area3D.xml @@ -7,6 +7,7 @@ 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses. To give the area its shape, add a [CollisionShape3D] or a [CollisionPolygon3D] node as a [i]direct[/i] child (or add multiple such nodes as direct children) of the area. [b]Warning:[/b] See [ConcavePolygonShape3D] (also called "trimesh") for a warning about possibly unexpected behavior when using that shape for an area. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 21ccf79fe2..ce4d7693d8 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -679,7 +679,7 @@ </description> </operator> <operator name="operator []"> - <return type="void" /> + <return type="Variant" /> <param index="0" name="index" type="int" /> <description> Returns a reference to the element of type [Variant] at the specified location. Arrays start at index 0. [param index] can be a zero or positive value to start from the beginning, or a negative value to start from the end. Out-of-bounds array access causes a run-time error, which will result in an error being printed and the project execution pausing if run from the editor. diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index f7764d5e32..7b86afcc4c 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -65,11 +65,15 @@ <param index="1" name="arrays" type="Array" /> <param index="2" name="blend_shapes" type="Array[]" default="[]" /> <param index="3" name="lods" type="Dictionary" default="{}" /> - <param index="4" name="compress_flags" type="int" enum="Mesh.ArrayFormat" default="0" /> - <description> - Creates a new surface. - Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface. - The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. + <param index="4" name="flags" type="int" enum="Mesh.ArrayFormat" default="0" /> + <description> + Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface. + Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType]. + The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. + The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code]. + The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used. + The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. + [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles. </description> </method> <method name="clear_blend_shapes"> diff --git a/doc/classes/AudioStreamPlaybackPolyphonic.xml b/doc/classes/AudioStreamPlaybackPolyphonic.xml new file mode 100644 index 0000000000..8b0951153b --- /dev/null +++ b/doc/classes/AudioStreamPlaybackPolyphonic.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamPlaybackPolyphonic" inherits="AudioStreamPlayback" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Playback instance for [AudioStreamPolyphonic]. + </brief_description> + <description> + Playback instance for [AudioStreamPolyphonic]. After setting the [code]stream[/code] property of [AudioStreamPlayer], [AudioStreamPlayer2D], or [AudioStreamPlayer3D], the playback instance can be obtained by calling [method AudioStreamPlayer.get_stream_playback], [method AudioStreamPlayer2D.get_stream_playback] or [method AudioStreamPlayer3D.get_stream_playback] methods. + </description> + <tutorials> + </tutorials> + <methods> + <method name="is_stream_playing" qualifiers="const"> + <return type="bool" /> + <param index="0" name="stream" type="int" /> + <description> + Return true whether the stream associated with an integer ID is still playing. Check [method play_stream] for information on when this ID becomes invalid. + </description> + </method> + <method name="play_stream"> + <return type="int" /> + <param index="0" name="stream" type="AudioStream" /> + <param index="1" name="from_offset" type="float" default="0" /> + <param index="2" name="volume_db" type="float" default="0" /> + <param index="3" name="pitch_scale" type="float" default="1.0" /> + <description> + Play an [AudioStream] at a given offset, volume and pitch scale. Playback starts immediately. + The return value is an unique integer ID that is associated to this playback stream and which can be used to control it. + This ID becomes invalid when the stream ends (if it does not loop), when the [AudioStreamPlaybackPolyphonic] is stopped, or when [method stop_stream] is called. + This function returns [constant INVALID_ID] if the amount of streams currently playing equals [member AudioStreamPolyphonic.polyphony]. If you need a higher amount of maximum polyphony, raise this value. + </description> + </method> + <method name="set_stream_pitch_scale"> + <return type="void" /> + <param index="0" name="stream" type="int" /> + <param index="1" name="pitch_scale" type="float" /> + <description> + Change the stream pitch scale. The [param stream] argument is an integer ID returned by [method play_stream]. + </description> + </method> + <method name="set_stream_volume"> + <return type="void" /> + <param index="0" name="stream" type="int" /> + <param index="1" name="volume_db" type="float" /> + <description> + Change the stream volume (in db). The [param stream] argument is an integer ID returned by [method play_stream]. + </description> + </method> + <method name="stop_stream"> + <return type="void" /> + <param index="0" name="stream" type="int" /> + <description> + Stop a stream. The [param stream] argument is an integer ID returned by [method play_stream], which becomes invalid after calling this function. + </description> + </method> + </methods> + <constants> + <constant name="INVALID_ID" value="-1"> + Returned by [method play_stream] in case it could not allocate a stream for playback. + </constant> + </constants> +</class> diff --git a/doc/classes/AudioStreamPolyphonic.xml b/doc/classes/AudioStreamPolyphonic.xml new file mode 100644 index 0000000000..baa1fc7037 --- /dev/null +++ b/doc/classes/AudioStreamPolyphonic.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamPolyphonic" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player. + </brief_description> + <description> + AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player. + Playback control is done via the [AudioStreamPlaybackPolyphonic] instance set inside the player, which can be obtained via [method AudioStreamPlayer.get_stream_playback], [method AudioStreamPlayer2D.get_stream_playback] or [method AudioStreamPlayer3D.get_stream_playback] methods. Obtaining the playback instance is only valid after the [code]stream[/code] property is set as an [AudioStreamPolyphonic] in those players. + </description> + <tutorials> + </tutorials> + <members> + <member name="polyphony" type="int" setter="set_polyphony" getter="get_polyphony" default="32"> + Maximum amount of simultaneous streams that can be played. + </member> + </members> +</class> diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml index b2c5a1756f..be4a649b50 100644 --- a/doc/classes/BackBufferCopy.xml +++ b/doc/classes/BackBufferCopy.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="BackBufferCopy" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts through the [code]texture(SCREEN_TEXTURE, ...)[/code] function. + Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts using the screen texture (i.e. a uniform sampler with ``hint_screen_texture``). </brief_description> <description> - Node for back-buffering the currently-displayed screen. The region defined in the [BackBufferCopy] node is buffered with the content of the screen it covers, or the entire screen according to the copy mode set. Use the [code]texture(SCREEN_TEXTURE, ...)[/code] function in your shader scripts to access the buffer. + Node for back-buffering the currently-displayed screen. The region defined in the [BackBufferCopy] node is buffered with the content of the screen it covers, or the entire screen according to the copy mode set. Use the screen texture in your shader scripts to access the buffer. [b]Note:[/b] Since this node inherits from [Node2D] (and not [Control]), anchors and margins won't apply to child [Control]-derived nodes. This can be problematic when resizing the window. To avoid this, add [Control]-derived nodes as [i]siblings[/i] to the [BackBufferCopy] node instead of adding them as children. </description> <tutorials> diff --git a/doc/classes/CanvasGroup.xml b/doc/classes/CanvasGroup.xml index 37827defec..6eeff8fef3 100644 --- a/doc/classes/CanvasGroup.xml +++ b/doc/classes/CanvasGroup.xml @@ -9,8 +9,10 @@ [codeblock] shader_type canvas_item; + uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + void fragment() { - vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0); + vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0); if (c.a > 0.0001) { c.rgb /= c.a; diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index e79bb97a92..c3c768c12d 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -42,10 +42,12 @@ <param index="3" name="end_angle" type="float" /> <param index="4" name="point_count" type="int" /> <param index="5" name="color" type="Color" /> - <param index="6" name="width" type="float" default="1.0" /> + <param index="6" name="width" type="float" default="-1.0" /> <param index="7" name="antialiased" type="bool" default="false" /> <description> - Draws a unfilled arc between the given angles. The larger the value of [param point_count], the smoother the curve. See also [method draw_circle]. + Draws an unfilled arc between the given angles with a uniform [param color] and [param width] and optional antialiasing (supported only for positive [param width]). The larger the value of [param point_count], the smoother the curve. See also [method draw_circle]. + If [param width] is negative, then the arc is drawn using [constant RenderingServer.PRIMITIVE_LINE_STRIP]. This means that when the CanvasItem is scaled, the arc will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. + The arc is drawn from [param start_angle] towards the value of [param end_angle] so in clockwise direction if [code]start_angle < end_angle[/code] and counter-clockwise otherwise. Passing the same angles but in reversed order will produce the same arc. If absolute difference of [param start_angle] and [param end_angle] is greater than [constant @GDScript.TAU] radians, then a full circle arc is drawn (i.e. arc will not overlap itself). </description> </method> <method name="draw_char" qualifiers="const"> @@ -242,20 +244,22 @@ <return type="void" /> <param index="0" name="points" type="PackedVector2Array" /> <param index="1" name="color" type="Color" /> - <param index="2" name="width" type="float" default="1.0" /> + <param index="2" name="width" type="float" default="-1.0" /> <param index="3" name="antialiased" type="bool" default="false" /> <description> - Draws interconnected line segments with a uniform [param color] and [param width] and optional antialiasing. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon]. + Draws interconnected line segments with a uniform [param color] and [param width] and optional antialiasing (supported only for positive [param width]). When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon]. + If [param width] is negative, the polyline is drawn using [constant RenderingServer.PRIMITIVE_LINE_STRIP]. This means that when the CanvasItem is scaled, the polyline will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. </description> </method> <method name="draw_polyline_colors"> <return type="void" /> <param index="0" name="points" type="PackedVector2Array" /> <param index="1" name="colors" type="PackedColorArray" /> - <param index="2" name="width" type="float" default="1.0" /> + <param index="2" name="width" type="float" default="-1.0" /> <param index="3" name="antialiased" type="bool" default="false" /> <description> - Draws interconnected line segments with a uniform [param width] and segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon]. + Draws interconnected line segments with a uniform [param width] and segment-by-segment coloring, and optional antialiasing (supported only for positive [param width]). Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon]. + If [param width] is negative, then the polyline is drawn using [constant RenderingServer.PRIMITIVE_LINE_STRIP]. This means that when the CanvasItem is scaled, the polyline will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. </description> </method> <method name="draw_primitive"> diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index 821117122c..2ff207acb7 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -5,8 +5,9 @@ </brief_description> <description> Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a [AnimatableBody3D]. However, they have two main uses: - [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. - [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [AnimatableBody3D]), which allows them to be moved by code and push other bodies on their path. + [i]Kinematic characters:[/i] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. + [i]Kinematic motion:[/i] Character bodies can also be used for kinematic motion (same functionality as [AnimatableBody3D]), which allows them to be moved by code and push other bodies on their path. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="Kinematic character (2D)">$DOCS_URL/tutorials/physics/kinematic_character_2d.html</link> diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml index 3ceb8967a0..df40d2a4cf 100644 --- a/doc/classes/CodeEdit.xml +++ b/doc/classes/CodeEdit.xml @@ -132,12 +132,6 @@ Perform an indent as if the user activated the "ui_text_indent" action. </description> </method> - <method name="do_unindent"> - <return type="void" /> - <description> - Perform an unindent as if the user activated the "ui_text_unindent" action. - </description> - </method> <method name="fold_all_lines"> <return type="void" /> <description> @@ -423,7 +417,7 @@ <method name="unindent_lines"> <return type="void" /> <description> - Unindents selected lines, or in the case of no selection the caret line by one. + Unindents selected lines, or in the case of no selection the caret line by one. Same as performing "ui_text_unindent" action. </description> </method> <method name="update_code_completion_options"> diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml index c302963b92..01b0d88326 100644 --- a/doc/classes/CollisionObject3D.xml +++ b/doc/classes/CollisionObject3D.xml @@ -5,6 +5,7 @@ </brief_description> <description> CollisionObject3D is the base class for physics objects. It can hold any number of collision [Shape3D]s. Each shape must be assigned to a [i]shape owner[/i]. The CollisionObject3D can have any number of shape owners. Shape owners are not nodes and do not appear in the editor, but are accessible through code using the [code]shape_owner_*[/code] methods. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> </tutorials> @@ -216,13 +217,13 @@ <signal name="mouse_entered"> <description> Emitted when the mouse pointer enters any of this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. - [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject2D]'s area is small. This signal may also not be emitted if another [CollisionObject2D] is overlapping the [CollisionObject2D] in question. + [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject3D]'s area is small. This signal may also not be emitted if another [CollisionObject3D] is overlapping the [CollisionObject3D] in question. </description> </signal> <signal name="mouse_exited"> <description> Emitted when the mouse pointer exits all this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. - [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject2D]'s area is small. This signal may also not be emitted if another [CollisionObject2D] is overlapping the [CollisionObject2D] in question. + [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject3D]'s area is small. This signal may also not be emitted if another [CollisionObject3D] is overlapping the [CollisionObject3D] in question. </description> </signal> </signals> @@ -232,7 +233,7 @@ Automatically re-added to the physics simulation when the [Node] is processed again. </constant> <constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode"> - When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody3D] can't be affected by forces or other bodies while static. + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area3D]. [PhysicsBody3D] can't be affected by forces or other bodies while static. Automatically set [PhysicsBody3D] back to its original mode when the [Node] is processed again. </constant> <constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode"> diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml index 7d718cff27..29e55367a8 100644 --- a/doc/classes/CollisionPolygon3D.xml +++ b/doc/classes/CollisionPolygon3D.xml @@ -6,6 +6,7 @@ <description> Allows editing a concave or convex collision polygon's vertices on a selected plane. Can also set a depth perpendicular to that plane. This class is only available in the editor. It will not appear in the scene tree at run-time. Creates several [ConvexPolygonShape3D]s at run-time to represent the original polygon using convex decomposition. [b]Note:[/b] Since this is an editor-only helper, properties modified during gameplay will have no effect. + [b]Warning:[/b] A non-uniformly scaled CollisionPolygon3D node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change its [member polygon]'s vertices instead. </description> <tutorials> </tutorials> diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml index 304b46ba27..c5d05670e9 100644 --- a/doc/classes/CollisionShape3D.xml +++ b/doc/classes/CollisionShape3D.xml @@ -6,6 +6,7 @@ <description> Editor facility for creating and editing collision shapes in 3D space. Set the [member shape] property to configure the shape. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area3D] to give it a detection shape, or add it to a [PhysicsBody3D] to create a solid object. + [b]Warning:[/b] A non-uniformly scaled CollisionShape3D node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size of its [member shape] resource instead. </description> <tutorials> <link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index d1387d088d..57278d9241 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -101,7 +101,7 @@ <return type="Color" /> <param index="0" name="over" type="Color" /> <description> - Returns a new color resulting from overlaying this color over the given color. In a painting program, you can imagine it as the [param over] color painted over this colour (including alpha). + Returns a new color resulting from overlaying this color over the given color. In a painting program, you can imagine it as the [param over] color painted over this color (including alpha). [codeblocks] [gdscript] var bg = Color(0.0, 1.0, 0.0, 0.5) # Green with alpha of 50% diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml index 48b4df9126..ac2ea5be17 100644 --- a/doc/classes/ConfirmationDialog.xml +++ b/doc/classes/ConfirmationDialog.xml @@ -8,10 +8,10 @@ To get cancel action, you can use: [codeblocks] [gdscript] - get_cancel_button().pressed.connect(self.cancelled) + get_cancel_button().pressed.connect(self.canceled) [/gdscript] [csharp] - GetCancelButton().Pressed += Cancelled; + GetCancelButton().Pressed += Canceled; [/csharp] [/codeblocks] </description> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 75afb0cdbf..7082eff97d 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -196,12 +196,12 @@ </description> </method> <method name="_structured_text_parser" qualifiers="virtual const"> - <return type="Vector2i[]" /> + <return type="Vector3i[]" /> <param index="0" name="args" type="Array" /> <param index="1" name="text" type="String" /> <description> User defined BiDi algorithm override function. - Returns an [Array] of [Vector2i] text ranges, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately. + Returns an [Array] of [Vector3i] text ranges and text base directions, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately. </description> </method> <method name="accept_event"> diff --git a/doc/classes/ConvexPolygonShape3D.xml b/doc/classes/ConvexPolygonShape3D.xml index 32dc8f673b..66d2280280 100644 --- a/doc/classes/ConvexPolygonShape3D.xml +++ b/doc/classes/ConvexPolygonShape3D.xml @@ -4,7 +4,7 @@ Convex polygon shape resource for 3D physics. </brief_description> <description> - 3D convex polygon shape resource to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. Unlike [ConcavePolygonShape3D], [ConvexPolygonShape3D] cannot store concave polygon shapes. [ConvexPolygonShape2D]s can be manually drawn in the editor using the [CollisionPolygon3D] node. + 3D convex polygon shape resource to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. Unlike [ConcavePolygonShape3D], [ConvexPolygonShape3D] cannot store concave polygon shapes. [ConvexPolygonShape3D]s can be manually drawn in the editor using the [CollisionPolygon3D] node. [b]Convex decomposition:[/b] Concave objects' collisions can be represented accurately using [i]several[/i] [ConvexPolygonShape3D]s. This allows dynamic physics bodies to have complex concave collisions (at a performance cost). This is available in the editor by selecting the [MeshInstance3D], going to the [b]Mesh[/b] menu and choosing [b]Create Multiple Convex Collision Siblings[/b]. Alternatively, [method MeshInstance3D.create_multiple_convex_collisions] can be called in a script to perform this decomposition at run-time. [b]Performance:[/b] [ConvexPolygonShape3D] is faster to check collisions against compared to [ConcavePolygonShape3D], but it is slower than primitive collision shapes such as [SphereShape3D] or [BoxShape3D]. Its use should generally be limited to medium-sized objects that cannot have their collision accurately represented by a primitive shape. </description> diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml index 362d792b39..72ac95a700 100644 --- a/doc/classes/Curve3D.xml +++ b/doc/classes/Curve3D.xml @@ -198,7 +198,7 @@ <param index="1" name="tolerance_length" type="float" default="0.2" /> <description> Returns a list of points along the curve, with almost uniform density. [param max_stages] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care! - [param tolerance_length] controls the maximal distance between two neighbouring points, before the segment has to be subdivided. + [param tolerance_length] controls the maximal distance between two neighboring points, before the segment has to be subdivided. </description> </method> </methods> diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 1dc4dd3ff0..832adb6e98 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1695,7 +1695,7 @@ [b]Note:[/b] This flag is implemented on macOS. </constant> <constant name="WINDOW_FLAG_MOUSE_PASSTHROUGH" value="7" enum="WindowFlags"> - All mouse event as passed to the underlying window of the same application. + All mouse events are passed to the underlying window of the same application. </constant> <constant name="WINDOW_FLAG_MAX" value="8" enum="WindowFlags"> Max value of the [enum WindowFlags]. diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index cddf3662aa..5f33c68a7d 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -71,12 +71,6 @@ This will not import the file. To reimport, call [method reimport_files] or [method scan] methods. </description> </method> - <method name="update_script_classes"> - <return type="void" /> - <description> - Scans the script files and updates the list of custom class names. - </description> - </method> </methods> <signals> <signal name="filesystem_changed"> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 2124a97751..326c4f6456 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -41,6 +41,7 @@ <param index="0" name="object" type="Variant" /> <description> This function is used for plugins that edit specific object types (nodes or resources). It requests the editor to edit the given object. + [param object] can be [code]null[/code] if the plugin was editing an object, but there is no longer any selected object handled by this plugin. It can be used to cleanup editing state. </description> </method> <method name="_enable_plugin" qualifiers="virtual"> @@ -467,6 +468,14 @@ See [method add_inspector_plugin] for an example of how to register a plugin. </description> </method> + <method name="add_resource_conversion_plugin"> + <return type="void" /> + <param index="0" name="plugin" type="EditorResourceConversionPlugin" /> + <description> + Registers a new [EditorResourceConversionPlugin]. Resource conversion plugins are used to add custom resource converters to the editor inspector. + See [EditorResourceConversionPlugin] for an example of how to create a resource conversion plugin. + </description> + </method> <method name="add_scene_format_importer_plugin"> <return type="void" /> <param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" /> @@ -632,6 +641,13 @@ Removes a gizmo plugin registered by [method add_node_3d_gizmo_plugin]. </description> </method> + <method name="remove_resource_conversion_plugin"> + <return type="void" /> + <param index="0" name="plugin" type="EditorResourceConversionPlugin" /> + <description> + Removes a resource conversion plugin registered by [method add_resource_conversion_plugin]. + </description> + </method> <method name="remove_scene_format_importer_plugin"> <return type="void" /> <param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" /> diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml index c40bb1d91e..6bdfbbe40c 100644 --- a/doc/classes/EditorResourceConversionPlugin.xml +++ b/doc/classes/EditorResourceConversionPlugin.xml @@ -1,8 +1,28 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="EditorResourceConversionPlugin" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Plugin for adding custom converters from one resource format to another in the editor resource picker context menu; for example, converting a [StandardMaterial3D] to a [ShaderMaterial]. </brief_description> <description> + [EditorResourceConversionPlugin] is invoked when the context menu is brought up for a resource in the editor inspector. Relevant conversion plugins will appear as menu options to convert the given resource to a target type. + Below shows an example of a basic plugin that will convert an [ImageTexture] to a [PortableCompressedTexture2D]. + [codeblocks] + [gdscript] + extends EditorResourceConversionPlugin + + func _handles(resource : Resource): + return resource is ImageTexture + + func _converts_to(): + return "PortableCompressedTexture2D" + + func _convert(itex : Resource): + var ptex = PortableCompressedTexture2D.new() + ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS) + return ptex + [/gdscript] + [/codeblocks] + To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first. </description> <tutorials> </tutorials> @@ -11,17 +31,20 @@ <return type="Resource" /> <param index="0" name="resource" type="Resource" /> <description> + Takes an input [Resource] and converts it to the type given in [method _converts_to]. The returned [Resource] is the result of the conversion, and the input [Resource] remains unchanged. </description> </method> <method name="_converts_to" qualifiers="virtual const"> <return type="String" /> <description> + Returns the class name of the target type of [Resource] that this plugin converts source resources to. </description> </method> <method name="_handles" qualifiers="virtual const"> <return type="bool" /> <param index="0" name="resource" type="Resource" /> <description> + Called to determine whether a particular [Resource] can be converted to the target resource type by this plugin. </description> </method> </methods> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index fca87f6a56..9015a12b43 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -433,12 +433,24 @@ The size to use for port previews in the visual shader uniforms (toggled by clicking the "eye" icon next to an output). The value is defined in pixels at 100% zoom, and will scale with zoom automatically. </member> <member name="filesystem/directories/autoscan_project_path" type="String" setter="" getter=""> - The folder where projects should be scanned for (recursively), in a way similar to the project manager's [b]Scan[/b]button. This can be set to the same value as [member filesystem/directories/default_project_path] for convenience. + The folder where projects should be scanned for (recursively), in a way similar to the project manager's [b]Scan[/b] button. This can be set to the same value as [member filesystem/directories/default_project_path] for convenience. [b]Note:[/b] Setting this path to a folder with very large amounts of files/folders can slow down the project manager startup significantly. To keep the project manager quick to start up, it is recommended to set this value to a folder as "specific" as possible. </member> <member name="filesystem/directories/default_project_path" type="String" setter="" getter=""> The folder where new projects should be created by default when clicking the project manager's [b]New Project[/b] button. This can be set to the same value as [member filesystem/directories/autoscan_project_path] for convenience. </member> + <member name="filesystem/external_programs/3d_model_editor" type="String" setter="" getter=""> + The program that opens 3D model scene files when clicking "Open in External Program" option in Filesystem Dock. If not specified, the file will be opened in the system's default program. + </member> + <member name="filesystem/external_programs/audio_editor" type="String" setter="" getter=""> + The program that opens audio files when clicking "Open in External Program" option in Filesystem Dock. If not specified, the file will be opened in the system's default program. + </member> + <member name="filesystem/external_programs/raster_image_editor" type="String" setter="" getter=""> + The program that opens raster image files when clicking "Open in External Program" option in Filesystem Dock. If not specified, the file will be opened in the system's default program. + </member> + <member name="filesystem/external_programs/vector_image_editor" type="String" setter="" getter=""> + The program that opens vector image files when clicking "Open in External Program" option in Filesystem Dock. If not specified, the file will be opened in the system's default program. + </member> <member name="filesystem/file_dialog/display_mode" type="int" setter="" getter=""> The display mode to use in the editor's file dialogs. - [b]Thumbnails[/b] takes more space, but displays dynamic resource thumbnails, making resources easier to preview without having to open them. diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml index b80857a7bf..10479dfcfe 100644 --- a/doc/classes/ImporterMesh.xml +++ b/doc/classes/ImporterMesh.xml @@ -27,9 +27,13 @@ <param index="5" name="name" type="String" default="""" /> <param index="6" name="flags" type="int" default="0" /> <description> - Creates a new surface, analogous to [method ArrayMesh.add_surface_from_arrays]. - Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface. - The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. + Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface. + Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType]. + The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. + The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code]. + The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used. + The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. + [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles. </description> </method> <method name="clear"> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index a0d2d93a7d..6ecf903fde 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -297,6 +297,7 @@ [param hotspot] must be within [param image]'s size. [b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If using an [AnimatedTexture], only the first frame will be displayed. [b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or [b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] compression mode can't be used for custom cursors. + [b]Note:[/b] On the web platform, the maximum allowed cursor image size is 128×128. Cursor images larger than 32×32 will also only be displayed if the mouse cursor image is entirely located within the page for [url=https://chromestatus.com/feature/5825971391299584]security reasons[/url]. </description> </method> <method name="set_default_cursor_shape"> diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 93731cf553..6fe53dfaac 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="JSON" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="JSON" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Helper class for creating and parsing JSON data. </brief_description> @@ -49,13 +49,21 @@ Returns an empty string if the last call to [method parse] was successful, or the error message if it failed. </description> </method> + <method name="get_parsed_text" qualifiers="const"> + <return type="String" /> + <description> + Return the text parsed by [method parse] as long as the function is instructed to keep it. + </description> + </method> <method name="parse"> <return type="int" enum="Error" /> - <param index="0" name="json_string" type="String" /> + <param index="0" name="json_text" type="String" /> + <param index="1" name="keep_text" type="bool" default="false" /> <description> - Attempts to parse the [param json_string] provided. + Attempts to parse the [param json_text] provided. Returns an [enum Error]. If the parse was successful, it returns [constant OK] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. Non-static variant of [method parse_string], if you want custom error handling. + The optional [param keep_text] argument instructs the parser to keep a copy of the original text. This text can be obtained later by using the [method get_parsed_text] function and is used when saving the resource (instead of generating new text from [member data]). </description> </method> <method name="parse_string" qualifiers="static"> diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index fe7756faaf..95c39d535e 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -80,7 +80,7 @@ A typical household lightbulb can range from around 600 lumens to 1,200 lumens, a candle is about 13 lumens, while a streetlight can be approximately 60,000 lumens. </member> <member name="light_intensity_lux" type="float" setter="set_param" getter="get_param"> - Used by [DirectionalLight3D]s when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code]. Sets the intensity of the light source measured in Lux. Lux is a measure pf luminous flux per unit area, it is equal to one lumen per square metre. Lux is the measure of how much light hits a surface at a given time. + Used by [DirectionalLight3D]s when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code]. Sets the intensity of the light source measured in Lux. Lux is a measure of luminous flux per unit area, it is equal to one lumen per square meter. Lux is the measure of how much light hits a surface at a given time. On a clear sunny day a surface in direct sunlight may be approximately 100,000 lux, a typical room in a home may be approximately 50 lux, while the moonlit ground may be approximately 0.1 lux. </member> <member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false"> diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml index 53dae1a8e6..723e6bbf21 100644 --- a/doc/classes/LightmapGI.xml +++ b/doc/classes/LightmapGI.xml @@ -93,22 +93,28 @@ <constant name="BAKE_ERROR_OK" value="0" enum="BakeError"> Lightmap baking was successful. </constant> - <constant name="BAKE_ERROR_NO_LIGHTMAPPER" value="1" enum="BakeError"> + <constant name="BAKE_ERROR_NO_SCENE_ROOT" value="1" enum="BakeError"> + Lightmap baking failed because the root node for the edited scene could not be accessed. + </constant> + <constant name="BAKE_ERROR_FOREIGN_DATA" value="2" enum="BakeError"> + Lightmap baking failed as the lightmap data resource is embedded in a foreign resource. + </constant> + <constant name="BAKE_ERROR_NO_LIGHTMAPPER" value="3" enum="BakeError"> Lightmap baking failed as there is no lightmapper available in this Godot build. </constant> - <constant name="BAKE_ERROR_NO_SAVE_PATH" value="2" enum="BakeError"> + <constant name="BAKE_ERROR_NO_SAVE_PATH" value="4" enum="BakeError"> Lightmap baking failed as the [LightmapGIData] save path isn't configured in the resource. </constant> - <constant name="BAKE_ERROR_NO_MESHES" value="3" enum="BakeError"> + <constant name="BAKE_ERROR_NO_MESHES" value="5" enum="BakeError"> Lightmap baking failed as there are no meshes whose [member GeometryInstance3D.gi_mode] is [constant GeometryInstance3D.GI_MODE_STATIC] and with valid UV2 mapping in the current scene. You may need to select 3D scenes in the Import dock and change their global illumination mode accordingly. </constant> - <constant name="BAKE_ERROR_MESHES_INVALID" value="4" enum="BakeError"> + <constant name="BAKE_ERROR_MESHES_INVALID" value="6" enum="BakeError"> Lightmap baking failed as the lightmapper failed to analyze some of the meshes marked as static for baking. </constant> - <constant name="BAKE_ERROR_CANT_CREATE_IMAGE" value="5" enum="BakeError"> + <constant name="BAKE_ERROR_CANT_CREATE_IMAGE" value="7" enum="BakeError"> Lightmap baking failed as the resulting image couldn't be saved or imported by Godot after it was saved. </constant> - <constant name="BAKE_ERROR_USER_ABORTED" value="6" enum="BakeError"> + <constant name="BAKE_ERROR_USER_ABORTED" value="8" enum="BakeError"> The user aborted the lightmap baking operation (typically by clicking the [b]Cancel[/b] button in the progress dialog). </constant> <constant name="ENVIRONMENT_MODE_DISABLED" value="0" enum="EnvironmentMode"> diff --git a/doc/classes/Marshalls.xml b/doc/classes/Marshalls.xml index 102e4b75ed..1eeb0be7ce 100644 --- a/doc/classes/Marshalls.xml +++ b/doc/classes/Marshalls.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Marshalls" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Data transformation (marshalling) and encoding helpers. + Data transformation (marshaling) and encoding helpers. </brief_description> <description> Provides data transformation and encoding utility functions. diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 94e80ffb2b..1c1f48588f 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -227,10 +227,10 @@ Contains custom color channel 3. [PackedByteArray] if [code](format >> [constant ARRAY_FORMAT_CUSTOM3_SHIFT]) & [constant ARRAY_FORMAT_CUSTOM_MASK])[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. </constant> <constant name="ARRAY_BONES" value="10" enum="ArrayType"> - [PackedFloat32Array] or [PackedInt32Array] of bone indices. Each element is a group of 4 numbers. + [PackedFloat32Array] or [PackedInt32Array] of bone indices. Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag. </constant> <constant name="ARRAY_WEIGHTS" value="11" enum="ArrayType"> - [PackedFloat32Array] of bone weights. Each element in groups of 4 floats. + [PackedFloat32Array] or [PackedFloat64Array] of bone weights in the range [code]0.0[/code] to [code]1.0[/code] (inclusive). Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag. </constant> <constant name="ARRAY_INDEX" value="12" enum="ArrayType"> [PackedInt32Array] of integers used as indices referencing vertices, colors, normals, tangents, and textures. All of those arrays must have the same number of elements as the vertex array. No index can be beyond the vertex array size. When this index array is present, it puts the function into "index mode," where the index selects the *i*'th vertex, normal, tangent, color, UV, etc. This means if you want to have different normals or colors along an edge, you have to duplicate the vertices. @@ -341,6 +341,9 @@ <constant name="ARRAY_FLAG_USE_8_BONE_WEIGHTS" value="134217728" enum="ArrayFormat" is_bitfield="true"> Flag used to mark that the mesh contains up to 8 bone influences per vertex. This flag indicates that [constant ARRAY_BONES] and [constant ARRAY_WEIGHTS] elements will have double length. </constant> + <constant name="ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY" value="268435456" enum="ArrayFormat" is_bitfield="true"> + Flag used to mark that the mesh intentionally contains no vertex array. + </constant> <constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode"> Blend shapes are normalized. </constant> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 6dab7b4ebe..0058bf8a2f 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -566,7 +566,7 @@ <method name="open_midi_inputs"> <return type="void" /> <description> - Initialises the singleton for the system MIDI driver. + Initializes the singleton for the system MIDI driver. [b]Note:[/b] This method is implemented on Linux, macOS and Windows. </description> </method> @@ -592,12 +592,12 @@ </description> </method> <method name="set_environment" qualifiers="const"> - <return type="bool" /> + <return type="void" /> <param index="0" name="variable" type="String" /> <param index="1" name="value" type="String" /> <description> Sets the value of the environment variable [param variable] to [param value]. The environment variable will be set for the Godot process and any process executed with [method execute] after running [method set_environment]. The environment variable will [i]not[/i] persist to processes run after the Godot process was terminated. - [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows. + [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character. On Windows, there is a 32767 characters limit for the combined length of [param variable], [param value], and the [code]=[/code] and null terminator characters that will be registered in the environment block. </description> </method> <method name="set_restart_on_exit"> @@ -637,6 +637,14 @@ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS and Windows. </description> </method> + <method name="unset_environment" qualifiers="const"> + <return type="void" /> + <param index="0" name="variable" type="String" /> + <description> + Removes the environment [param variable] from the current environment, if it exists. The environment variable will be removed for the Godot process and any process executed with [method execute] after running [method unset_environment]. The removal of the environment variable will [i]not[/i] persist to processes run after the Godot process was terminated. + [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character. + </description> + </method> </methods> <members> <member name="low_processor_usage_mode" type="bool" setter="set_low_processor_usage_mode" getter="is_in_low_processor_usage_mode" default="false"> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index a9e17f4666..1a805007e6 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -883,7 +883,7 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="value" type="Variant" /> <description> - Adds or changes the entry [param name] inside the object's metadata. The metadata [param value] can be any [Variant], although some types cannot be serialised correctly. + Adds or changes the entry [param name] inside the object's metadata. The metadata [param value] can be any [Variant], although some types cannot be serialized correctly. If [param value] is [code]null[/code], the entry is removed. This is the equivalent of using [method remove_meta]. See also [method has_meta] and [method get_meta]. [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector dock and should not be edited. </description> diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml index 0768df31cc..f38130fe0c 100644 --- a/doc/classes/PhysicalBone3D.xml +++ b/doc/classes/PhysicalBone3D.xml @@ -3,6 +3,7 @@ <brief_description> </brief_description> <description> + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> </tutorials> diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index 2ef54683f2..3e100e3280 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -4,7 +4,8 @@ Base class for all objects affected by physics in 3D space. </brief_description> <description> - PhysicsBody3D is an abstract base class for implementing a physics body. All *Body types inherit from it. + PhysicsBody3D is an abstract base class for implementing a physics body. All *Body3D types inherit from it. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link> diff --git a/doc/classes/PhysicsServer3DManager.xml b/doc/classes/PhysicsServer3DManager.xml index 3ec03fede4..4d789ceb3f 100644 --- a/doc/classes/PhysicsServer3DManager.xml +++ b/doc/classes/PhysicsServer3DManager.xml @@ -15,7 +15,7 @@ <param index="0" name="name" type="String" /> <param index="1" name="create_callback" type="Callable" /> <description> - Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object. + Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer3D] object. </description> </method> <method name="set_default_server"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 9e1c751662..ec05be368c 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -384,6 +384,9 @@ <member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to true. </member> + <member name="debug/gdscript/warnings/confusable_identifier" type="int" setter="" getter="" default="1"> + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier contains characters that can be confused with something else, like when mixing different alphabets. + </member> <member name="debug/gdscript/warnings/constant_used_as_function" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a constant is used as a function. </member> @@ -615,8 +618,17 @@ Main window content is expanded to the full size of the window. Unlike a borderless window, the frame is left intact and can be used to resize the window, and the title bar is transparent, but has minimize/maximize/close buttons. [b]Note:[/b] This setting is implemented only on macOS. </member> - <member name="display/window/size/initial_screen" type="int" setter="" getter="" default="-2"> - Main window initial screen. + <member name="display/window/size/initial_position" type="Vector2i" setter="" getter="" default="Vector2i(0, 0)"> + Main window initial position (in virtual desktop coordinates), this settings is used only if [member display/window/size/initial_position_type] is set to "Absolute" ([code]0[/code]). + </member> + <member name="display/window/size/initial_position_type" type="int" setter="" getter="" default="1"> + Main window initial position. + [code]0[/code] - "Absolute", [member display/window/size/initial_position] is used to set window position. + [code]1[/code] - "Primary Screen Center". + [code]2[/code] - "Other Screen Center", [member display/window/size/initial_screen] is used to set window position. + </member> + <member name="display/window/size/initial_screen" type="int" setter="" getter="" default="0"> + Main window initial screen, this settings is used only if [member display/window/size/initial_position_type] is set to "Other Screen Center" ([code]2[/code]). </member> <member name="display/window/size/mode" type="int" setter="" getter="" default="0"> Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves. @@ -652,6 +664,13 @@ See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application. Depending on the platform and used renderer, the engine will fall back to [code]Enabled[/code], if the desired mode is not supported. </member> + <member name="dotnet/project/assembly_name" type="String" setter="" getter="" default=""""> + Name of the .NET assembly. This name is used as the name of the [code].csproj[/code] and [code].sln[/code] files. By default, it's set to the name of the project ([member application/config/name]) allowing to change it in the future without affecting the .NET assembly. + </member> + <member name="dotnet/project/solution_directory" type="String" setter="" getter="" default=""""> + Directory that contains the [code].sln[/code] file. By default, the [code].sln[/code] files is in the root of the project directory, next to the [code]project.godot[/code] and [code].csproj[/code] files. + Changing this value allows setting up a multi-project scenario where there are multiple [code].csproj[/code]. Keep in mind that the Godot project is considered one of the C# projects in the workspace and it's root directory should contain the [code]project.godot[/code] and [code].csproj[/code] next to each other. + </member> <member name="editor/movie_writer/disable_vsync" type="bool" setter="" getter="" default="false"> If [code]true[/code], requests V-Sync to be disabled when writing a movie (similar to setting [member display/window/vsync/vsync_mode] to [b]Disabled[/b]). This can speed up video writing if the hardware is fast enough to render, encode and save the video at a framerate higher than the monitor's refresh rate. [b]Note:[/b] [member editor/movie_writer/disable_vsync] has no effect if the operating system or graphics driver forces V-Sync with no way for applications to disable it. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 32281953b2..fc08a16619 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -291,7 +291,7 @@ <param index="0" name="item" type="RID" /> <param index="1" name="points" type="PackedVector2Array" /> <param index="2" name="colors" type="PackedColorArray" /> - <param index="3" name="width" type="float" default="1.0" /> + <param index="3" name="width" type="float" default="-1.0" /> <param index="4" name="antialiased" type="bool" default="false" /> <description> </description> @@ -3336,7 +3336,7 @@ <param index="0" name="viewport" type="RID" /> <param index="1" name="enabled" type="bool" /> <description> - If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size. + If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the screen_texture. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size. </description> </method> <method name="viewport_set_scaling_3d_mode"> @@ -3810,6 +3810,8 @@ </constant> <constant name="ARRAY_FLAG_USE_8_BONE_WEIGHTS" value="134217728" enum="ArrayFormat" is_bitfield="true"> </constant> + <constant name="ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY" value="268435456" enum="ArrayFormat" is_bitfield="true"> + </constant> <constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType"> Primitive to draw consists of points. </constant> diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml index 2b6376f2cd..bb55123b37 100644 --- a/doc/classes/ResourceFormatLoader.xml +++ b/doc/classes/ResourceFormatLoader.xml @@ -38,6 +38,13 @@ Gets the list of extensions for files this loader is able to read. </description> </method> + <method name="_get_resource_script_class" qualifiers="virtual const"> + <return type="String" /> + <param index="0" name="path" type="String" /> + <description> + Returns the script class name associated with the [Resource] under the given [param path]. If the resource has no script or the script isn't a named class, it should return [code]""[/code]. + </description> + </method> <method name="_get_resource_type" qualifiers="virtual const"> <return type="String" /> <param index="0" name="path" type="String" /> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index dd291a425d..5550bf0955 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -283,6 +283,7 @@ <return type="void" /> <param index="0" name="font_size" type="int" /> <description> + Adds a [code][font_size][/code] tag to the tag stack. Overrides default font size for its duration. </description> </method> <method name="push_hint"> diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml index 8380d56de3..148cdf96ee 100644 --- a/doc/classes/RigidBody3D.xml +++ b/doc/classes/RigidBody3D.xml @@ -8,6 +8,7 @@ You can switch the body's behavior using [member lock_rotation], [member freeze], and [member freeze_mode]. [b]Note:[/b] Don't change a RigidBody3D's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state. If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator]. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link> diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml index 75f835260a..c472ab647e 100644 --- a/doc/classes/Shader.xml +++ b/doc/classes/Shader.xml @@ -26,12 +26,12 @@ Returns the shader mode for the shader, either [constant MODE_CANVAS_ITEM], [constant MODE_SPATIAL] or [constant MODE_PARTICLES]. </description> </method> - <method name="has_parameter" qualifiers="const"> - <return type="bool" /> - <param index="0" name="name" type="StringName" /> + <method name="get_shader_uniform_list"> + <return type="Array" /> + <param index="0" name="get_groups" type="bool" default="false" /> <description> - Returns [code]true[/code] if the shader has this param defined as a uniform in its code. - [b]Note:[/b] [param name] must match the name of the uniform in the code exactly. + Get the list of shader uniforms that can be assigned to a [ShaderMaterial], for use with [method ShaderMaterial.set_shader_parameter] and [method ShaderMaterial.get_shader_parameter]. The parameters returned are contained in dictionaries in a similar format to the ones returned by [method Object.get_property_list]. + If argument [param get_groups] is true, parameter grouping hints will be provided. </description> </method> <method name="set_default_texture_parameter"> diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml index 808f93b491..39bdc5c796 100644 --- a/doc/classes/Skeleton2D.xml +++ b/doc/classes/Skeleton2D.xml @@ -16,7 +16,7 @@ <param index="0" name="delta" type="float" /> <param index="1" name="execution_mode" type="int" /> <description> - Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton3D has one assigned. + Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton2D has one assigned. </description> </method> <method name="get_bone"> diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml index 77aaf0213b..3a78f13bff 100644 --- a/doc/classes/SkeletonModification2D.xml +++ b/doc/classes/SkeletonModification2D.xml @@ -56,7 +56,7 @@ <method name="get_modification_stack"> <return type="SkeletonModificationStack2D" /> <description> - Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on. + Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton2D the modification is operating on. </description> </method> <method name="set_editor_draw_gizmo"> diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml index 57bdd52d9e..6fb311bcee 100644 --- a/doc/classes/SkeletonProfile.xml +++ b/doc/classes/SkeletonProfile.xml @@ -5,6 +5,7 @@ </brief_description> <description> This resource is used in [EditorScenePostImport]. Some parameters are referring to bones in [Skeleton3D], [Skin], [Animation], and some other nodes are rewritten based on the parameters of [SkeletonProfile]. + [b]Note:[/b] These parameters need to be set only when creating a custom profile. In [SkeletonProfileHumanoid], they are defined internally as read-only values. </description> <tutorials> <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link> @@ -160,16 +161,18 @@ </methods> <members> <member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" default="0"> + The amount of bones in retargeting section's [BoneMap] editor. For example, [SkeletonProfileHumanoid] has 56 bones. + The size of elements in [BoneMap] updates when changing this property in it's assigned [SkeletonProfile]. </member> <member name="group_size" type="int" setter="set_group_size" getter="get_group_size" default="0"> + The amount of groups of bones in retargeting section's [BoneMap] editor. For example, [SkeletonProfileHumanoid] has 4 groups. + This property exists to separate the bone list into several sections in the editor. </member> <member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&"""> - A name of bone that will be used as the root bone in [AnimationTree]. - [b]Note:[/b] In most cases, it is the bone of the parent of the hips that exists at the world origin in the humanoid model. + A bone name that will be used as the root bone in [AnimationTree]. This should be the bone of the parent of hips that exists at the world origin. </member> <member name="scale_base_bone" type="StringName" setter="set_scale_base_bone" getter="get_scale_base_bone" default="&"""> - A name of bone which height will be used as the coefficient for normalization. - [b]Note:[/b] In most cases, it is hips in the humanoid model. + A bone name which will use model's height as the coefficient for normalization. For example, [SkeletonProfileHumanoid] defines it as [code]Hips[/code]. </member> </members> <signals> diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml index 87b823bd2a..195f3598d5 100644 --- a/doc/classes/SpriteFrames.xml +++ b/doc/classes/SpriteFrames.xml @@ -5,7 +5,6 @@ </brief_description> <description> Sprite frame library for an [AnimatedSprite2D] or [AnimatedSprite3D] node. Contains frames and animation data for playback. - [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps. </description> <tutorials> </tutorials> @@ -14,7 +13,7 @@ <return type="void" /> <param index="0" name="anim" type="StringName" /> <description> - Adds a new animation to the library. + Adds a new [param anim] animation to the library. </description> </method> <method name="add_frame"> @@ -24,20 +23,20 @@ <param index="2" name="duration" type="float" default="1.0" /> <param index="3" name="at_position" type="int" default="-1" /> <description> - Adds a frame to the given animation. + Adds a frame to the [param anim] animation. If [param at_position] is [code]-1[/code], the frame will be added to the end of the animation. </description> </method> <method name="clear"> <return type="void" /> <param index="0" name="anim" type="StringName" /> <description> - Removes all frames from the given animation. + Removes all frames from the [param anim] animation. </description> </method> <method name="clear_all"> <return type="void" /> <description> - Removes all animations. A "default" animation will be created. + Removes all animations. An empty [code]default[/code] animation will be created. </description> </method> <method name="get_animation_loop" qualifiers="const"> @@ -91,14 +90,14 @@ <return type="bool" /> <param index="0" name="anim" type="StringName" /> <description> - If [code]true[/code], the named animation exists. + Returns [code]true[/code] if the [param anim] animation exists. </description> </method> <method name="remove_animation"> <return type="void" /> <param index="0" name="anim" type="StringName" /> <description> - Removes the given animation. + Removes the [param anim] animation. </description> </method> <method name="remove_frame"> @@ -106,7 +105,7 @@ <param index="0" name="anim" type="StringName" /> <param index="1" name="idx" type="int" /> <description> - Removes the animation's selected frame. + Removes the [param anim] animation's frame [param idx]. </description> </method> <method name="rename_animation"> @@ -114,7 +113,7 @@ <param index="0" name="anim" type="StringName" /> <param index="1" name="newname" type="StringName" /> <description> - Changes the animation's name to [param newname]. + Changes the [param anim] animation's name to [param newname]. </description> </method> <method name="set_animation_loop"> @@ -122,7 +121,7 @@ <param index="0" name="anim" type="StringName" /> <param index="1" name="loop" type="bool" /> <description> - If [code]true[/code], the animation will loop. + If [param loop] is [code]true[/code], the [param anim] animation will loop when it reaches the end, or the start if it is played in reverse. </description> </method> <method name="set_animation_speed"> @@ -140,7 +139,7 @@ <param index="2" name="texture" type="Texture2D" /> <param index="3" name="duration" type="float" default="1.0" /> <description> - Sets the texture and the duration of the frame [param idx] in the [param anim] animation. + Sets the [param texture] and the [param duration] of the frame [param idx] in the [param anim] animation. </description> </method> </methods> diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml index 0beaa6bb52..7bebd46004 100644 --- a/doc/classes/StaticBody3D.xml +++ b/doc/classes/StaticBody3D.xml @@ -7,8 +7,9 @@ Static body for 3D physics. A static body is a simple body that doesn't move under physics simulation, i.e. it can't be moved by external forces or contacts but its transformation can still be updated manually by the user. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], it doesn't consume any CPU resources as long as they don't move. They have extra functionalities to move and affect other bodies: - [b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path. - [b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels. + [i]Static transform change:[/i] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path. + [i]Constant velocity:[/i] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml index ff6d4d8821..4a63f4488c 100644 --- a/doc/classes/StyleBox.xml +++ b/doc/classes/StyleBox.xml @@ -17,21 +17,16 @@ <description> </description> </method> - <method name="_get_center_size" qualifiers="virtual const"> - <return type="Vector2" /> - <description> - </description> - </method> <method name="_get_draw_rect" qualifiers="virtual const"> <return type="Rect2" /> <param index="0" name="rect" type="Rect2" /> <description> </description> </method> - <method name="_get_style_margin" qualifiers="virtual const"> - <return type="float" /> - <param index="0" name="side" type="int" enum="Side" /> + <method name="_get_minimum_size" qualifiers="virtual const"> + <return type="Vector2" /> <description> + Virtual method to be implemented by the user. Returns a custom minimum size that the stylebox must respect when drawing. By default [method get_minimum_size] only takes content margins into account. This method can be overridden to add another size restriction. A combination of the default behavior and the output of this method will be used, to account for both sizes. </description> </method> <method name="_test_mask" qualifiers="virtual const"> @@ -50,10 +45,11 @@ The [RID] value can either be the result of [method CanvasItem.get_canvas_item] called on an existing [CanvasItem]-derived node, or directly from creating a canvas item in the [RenderingServer] with [method RenderingServer.canvas_item_create]. </description> </method> - <method name="get_center_size" qualifiers="const"> - <return type="Vector2" /> + <method name="get_content_margin" qualifiers="const"> + <return type="float" /> + <param index="0" name="margin" type="int" enum="Side" /> <description> - Returns the size of this [StyleBox] without the margins. + Returns the default margin of the specified [enum Side]. </description> </method> <method name="get_current_item_drawn" qualifiers="const"> @@ -62,13 +58,6 @@ Returns the [CanvasItem] that handles its [constant CanvasItem.NOTIFICATION_DRAW] or [method CanvasItem._draw] callback at this moment. </description> </method> - <method name="get_default_margin" qualifiers="const"> - <return type="float" /> - <param index="0" name="margin" type="int" enum="Side" /> - <description> - Returns the default margin of the specified [enum Side]. - </description> - </method> <method name="get_margin" qualifiers="const"> <return type="float" /> <param index="0" name="margin" type="int" enum="Side" /> @@ -89,7 +78,7 @@ Returns the "offset" of a stylebox. This helper function returns a value equivalent to [code]Vector2(style.get_margin(MARGIN_LEFT), style.get_margin(MARGIN_TOP))[/code]. </description> </method> - <method name="set_default_margin"> + <method name="set_content_margin"> <return type="void" /> <param index="0" name="margin" type="int" enum="Side" /> <param index="1" name="offset" type="float" /> @@ -97,7 +86,7 @@ Sets the default value of the specified [enum Side] to [param offset] pixels. </description> </method> - <method name="set_default_margin_all"> + <method name="set_content_margin_all"> <return type="void" /> <param index="0" name="offset" type="float" /> <description> @@ -114,21 +103,21 @@ </method> </methods> <members> - <member name="content_margin_bottom" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> + <member name="content_margin_bottom" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0"> The bottom margin for the contents of this style box. Increasing this value reduces the space available to the contents from the bottom. If this value is negative, it is ignored and a child-specific margin is used instead. For example for [StyleBoxFlat] the border thickness (if any) is used instead. It is up to the code using this style box to decide what these contents are: for example, a [Button] respects this content margin for the textual contents of the button. [method get_margin] should be used to fetch this value as consumer instead of reading these properties directly. This is because it correctly respects negative values and the fallback mentioned above. </member> - <member name="content_margin_left" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> + <member name="content_margin_left" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0"> The left margin for the contents of this style box. Increasing this value reduces the space available to the contents from the left. Refer to [member content_margin_bottom] for extra considerations. </member> - <member name="content_margin_right" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> + <member name="content_margin_right" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0"> The right margin for the contents of this style box. Increasing this value reduces the space available to the contents from the right. Refer to [member content_margin_bottom] for extra considerations. </member> - <member name="content_margin_top" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> + <member name="content_margin_top" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0"> The top margin for the contents of this style box. Increasing this value reduces the space available to the contents from the top. Refer to [member content_margin_bottom] for extra considerations. </member> diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml index aeba777b43..745187ed63 100644 --- a/doc/classes/StyleBoxTexture.xml +++ b/doc/classes/StyleBoxTexture.xml @@ -9,36 +9,36 @@ <tutorials> </tutorials> <methods> - <method name="get_expand_margin_size" qualifiers="const"> + <method name="get_expand_margin" qualifiers="const"> <return type="float" /> <param index="0" name="margin" type="int" enum="Side" /> <description> Returns the expand margin size of the specified [enum Side]. </description> </method> - <method name="get_margin_size" qualifiers="const"> + <method name="get_texture_margin" qualifiers="const"> <return type="float" /> <param index="0" name="margin" type="int" enum="Side" /> <description> Returns the margin size of the specified [enum Side]. </description> </method> - <method name="set_expand_margin_all"> + <method name="set_expand_margin"> <return type="void" /> - <param index="0" name="size" type="float" /> + <param index="0" name="margin" type="int" enum="Side" /> + <param index="1" name="size" type="float" /> <description> - Sets the expand margin to [param size] pixels for all margins. + Sets the expand margin to [param size] pixels for the specified [enum Side]. </description> </method> - <method name="set_expand_margin_size"> + <method name="set_expand_margin_all"> <return type="void" /> - <param index="0" name="margin" type="int" enum="Side" /> - <param index="1" name="size" type="float" /> + <param index="0" name="size" type="float" /> <description> - Sets the expand margin to [param size] pixels for the specified [enum Side]. + Sets the expand margin to [param size] pixels for all margins. </description> </method> - <method name="set_margin_size"> + <method name="set_texture_margin"> <return type="void" /> <param index="0" name="margin" type="int" enum="Side" /> <param index="1" name="size" type="float" /> @@ -46,7 +46,7 @@ Sets the margin to [param size] pixels for the specified [enum Side]. </description> </method> - <method name="set_margin_size_all"> + <method name="set_texture_margin_all"> <return type="void" /> <param index="0" name="size" type="float" /> <description> @@ -64,48 +64,48 @@ <member name="draw_center" type="bool" setter="set_draw_center" getter="is_draw_center_enabled" default="true"> If [code]true[/code], the nine-patch texture's center tile will be drawn. </member> - <member name="expand_margin_bottom" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0"> + <member name="expand_margin_bottom" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0"> Expands the bottom margin of this style box when drawing, causing it to be drawn larger than requested. </member> - <member name="expand_margin_left" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0"> + <member name="expand_margin_left" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0"> Expands the left margin of this style box when drawing, causing it to be drawn larger than requested. </member> - <member name="expand_margin_right" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0"> + <member name="expand_margin_right" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0"> Expands the right margin of this style box when drawing, causing it to be drawn larger than requested. </member> - <member name="expand_margin_top" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0"> + <member name="expand_margin_top" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0"> Expands the top margin of this style box when drawing, causing it to be drawn larger than requested. </member> - <member name="margin_bottom" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0"> + <member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + Modulates the color of the texture when this style box is drawn. + </member> + <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> + Species a sub-region of the texture to use. + This is equivalent to first wrapping the texture in an [AtlasTexture] with the same region. + </member> + <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> + The texture to use when drawing this style box. + </member> + <member name="texture_margin_bottom" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0"> Increases the bottom margin of the 3×3 texture box. A higher value means more of the source texture is considered to be part of the bottom border of the 3×3 box. This is also the value used as fallback for [member StyleBox.content_margin_bottom] if it is negative. </member> - <member name="margin_left" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0"> + <member name="texture_margin_left" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0"> Increases the left margin of the 3×3 texture box. A higher value means more of the source texture is considered to be part of the left border of the 3×3 box. This is also the value used as fallback for [member StyleBox.content_margin_left] if it is negative. </member> - <member name="margin_right" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0"> + <member name="texture_margin_right" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0"> Increases the right margin of the 3×3 texture box. A higher value means more of the source texture is considered to be part of the right border of the 3×3 box. This is also the value used as fallback for [member StyleBox.content_margin_right] if it is negative. </member> - <member name="margin_top" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0"> + <member name="texture_margin_top" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0"> Increases the top margin of the 3×3 texture box. A higher value means more of the source texture is considered to be part of the top border of the 3×3 box. This is also the value used as fallback for [member StyleBox.content_margin_top] if it is negative. </member> - <member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> - Modulates the color of the texture when this style box is drawn. - </member> - <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> - Species a sub-region of the texture to use. - This is equivalent to first wrapping the texture in an [AtlasTexture] with the same region. - </member> - <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> - The texture to use when drawing this style box. - </member> </members> <constants> <constant name="AXIS_STRETCH_MODE_STRETCH" value="0" enum="AxisStretchMode"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 1efd0f9326..ccd79cd170 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -696,7 +696,7 @@ <method name="merge_overlapping_carets"> <return type="void" /> <description> - Merges any overlapping carets. Will favour the newest caret, or the caret with a selection. + Merges any overlapping carets. Will favor the newest caret, or the caret with a selection. [b]Note:[/b] This is not called when a caret changes position but after certain actions, so it is possible to get into a state where carets overlap. </description> </method> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index d2c6dee373..711fb89217 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1042,7 +1042,7 @@ </description> </method> <method name="parse_structured_text" qualifiers="const"> - <return type="Vector2i[]" /> + <return type="Vector3i[]" /> <param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" /> <param index="1" name="args" type="Array" /> <param index="2" name="text" type="String" /> @@ -1634,6 +1634,9 @@ <constant name="DIRECTION_RTL" value="2" enum="Direction"> Text is written from right to left. </constant> + <constant name="DIRECTION_INHERITED" value="3" enum="Direction"> + Text writing direction is the same as base string writing direction. Used for BiDi override only. + </constant> <constant name="ORIENTATION_HORIZONTAL" value="0" enum="Orientation"> Text is written horizontally. </constant> @@ -1881,7 +1884,7 @@ Font have fixed-width characters. </constant> <constant name="STRUCTURED_TEXT_DEFAULT" value="0" enum="StructuredTextParser"> - Use default behavior. Same as [constant STRUCTURED_TEXT_NONE] unless specified otherwise in the control description. + Use default Unicode BiDi algorithm. </constant> <constant name="STRUCTURED_TEXT_URI" value="1" enum="StructuredTextParser"> BiDi override for URI. @@ -1896,8 +1899,8 @@ BiDi override for lists. Structured text options: list separator [code]String[/code]. </constant> - <constant name="STRUCTURED_TEXT_NONE" value="5" enum="StructuredTextParser"> - Use default Unicode BiDi algorithm. + <constant name="STRUCTURED_TEXT_GDSCRIPT" value="5" enum="StructuredTextParser"> + BiDi override for GDScript. </constant> <constant name="STRUCTURED_TEXT_CUSTOM" value="6" enum="StructuredTextParser"> User defined structured text BiDi override function. diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index e144b09eb6..f4b306cf96 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -896,7 +896,7 @@ </description> </method> <method name="_parse_structured_text" qualifiers="virtual const"> - <return type="Vector2i[]" /> + <return type="Vector3i[]" /> <param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" /> <param index="1" name="args" type="Array" /> <param index="2" name="text" type="String" /> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 8176901ff7..2fd42666b4 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -104,7 +104,8 @@ <param index="1" name="coords" type="Vector2i" /> <param index="2" name="use_proxies" type="bool" default="false" /> <description> - Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. + Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. Returns [code]-1[/code] if the cell does not exist. + If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. </description> </method> <method name="get_cell_tile_data" qualifiers="const"> @@ -113,8 +114,17 @@ <param index="1" name="coords" type="Vector2i" /> <param index="2" name="use_proxies" type="bool" default="false" /> <description> - Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell is not a [TileSetAtlasSource]. + Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. + [codeblock] + func get_clicked_tile_power(): + var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position()) + var data = tile_map.get_cell_tile_data(0, clicked_cell) + if data: + return data.get_custom_data("power") + else: + return 0 + [/codeblock] </description> </method> <method name="get_coords_for_body_rid"> @@ -185,7 +195,19 @@ <return type="Vector2i[]" /> <param index="0" name="layer" type="int" /> <description> - Returns a [Vector2] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1. + Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1. + </description> + </method> + <method name="get_used_cells_by_id" qualifiers="const"> + <return type="Vector2i[]" /> + <param index="0" name="layer" type="int" /> + <param index="1" name="source_id" type="int" default="-1" /> + <param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" /> + <param index="3" name="alternative_tile" type="int" default="-1" /> + <description> + Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]) or alternative id ([param source_id]). + If a parameter has it's value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default value, this method returns the same result as [method get_used_cells]. + A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1. </description> </method> <method name="get_used_rect"> diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 7fc6ba8161..a812b52307 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -589,7 +589,7 @@ <param index="0" name="terrain_set" type="int" /> <param index="1" name="mode" type="int" enum="TileSet.TerrainMode" /> <description> - Sets a terrain mode. Each mode determines which bits of a tile shape is used to match the neighbouring tiles' terrains. + Sets a terrain mode. Each mode determines which bits of a tile shape is used to match the neighboring tiles' terrains. </description> </method> </methods> diff --git a/doc/classes/VehicleBody3D.xml b/doc/classes/VehicleBody3D.xml index e1689133de..9f905c0ec5 100644 --- a/doc/classes/VehicleBody3D.xml +++ b/doc/classes/VehicleBody3D.xml @@ -7,6 +7,7 @@ This node implements all the physics logic needed to simulate a car. It is based on the raycast vehicle system commonly found in physics engines. You will need to add a [CollisionShape3D] for the main body of your vehicle and add [VehicleWheel3D] nodes for the wheels. You should also add a [MeshInstance3D] to this node for the 3D model of your car but this model should not include meshes for the wheels. You should control the vehicle by using the [member brake], [member engine_force], and [member steering] properties and not change the position or orientation of this node directly. [b]Note:[/b] The origin point of your VehicleBody3D will determine the center of gravity of your vehicle so it is better to keep this low and move the [CollisionShape3D] and [MeshInstance3D] upwards. [b]Note:[/b] This class has known issues and isn't designed to provide realistic 3D vehicle physics. If you want advanced vehicle physics, you will probably have to write your own physics integration using another [PhysicsBody3D] class. + [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead. </description> <tutorials> <link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/524</link> diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml index e069642e50..3781045c02 100644 --- a/doc/classes/VisualInstance3D.xml +++ b/doc/classes/VisualInstance3D.xml @@ -64,7 +64,7 @@ <member name="sorting_offset" type="float" setter="set_sorting_offset" getter="get_sorting_offset" default="0.0"> The sorting offset used by this [VisualInstance3D]. Adjusting it to a higher value will make the [VisualInstance3D] reliably draw on top of other [VisualInstance3D]s that are otherwise positioned at the same spot. </member> - <member name="sorting_use_aabb_center" type="bool" setter="set_sorting_use_aabb_center" getter="is_sorting_use_aabb_center" default="true"> + <member name="sorting_use_aabb_center" type="bool" setter="set_sorting_use_aabb_center" getter="is_sorting_use_aabb_center"> If [code]true[/code], the object is sorted based on the [AABB] center. The object will be sorted based on the global position otherwise. The [AABB] center based sorting is generally more accurate for 3D models. The position based sorting instead allows to better control the drawing order when working with [GPUParticles3D] and [CPUParticles3D]. </member> diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml index f95f871e52..685f5d5eef 100644 --- a/doc/classes/VisualShaderNode.xml +++ b/doc/classes/VisualShaderNode.xml @@ -58,13 +58,6 @@ Sets the output port index which will be showed for preview. If set to [code]-1[/code] no port will be open for preview. </member> </members> - <signals> - <signal name="editor_refresh_request"> - <description> - Emitted when the node requests an editor refresh. Currently called only in setter of [member VisualShaderNodeTexture.source], [VisualShaderNodeTexture], and [VisualShaderNodeCubemap] (and their derivatives). - </description> - </signal> - </signals> <constants> <constant name="PORT_TYPE_SCALAR" value="0" enum="PortType"> Floating-point scalar. Translated to [code]float[/code] type in shader code. diff --git a/doc/classes/VisualShaderNodeTexture.xml b/doc/classes/VisualShaderNodeTexture.xml index 72a7fadf1a..38fa98b21e 100644 --- a/doc/classes/VisualShaderNodeTexture.xml +++ b/doc/classes/VisualShaderNodeTexture.xml @@ -33,12 +33,18 @@ Use the texture from this shader's normal map built-in. </constant> <constant name="SOURCE_DEPTH" value="4" enum="Source"> - Use the depth texture available for this shader. + Use the depth texture captured during the depth prepass. Only available when the depth prepass is used (i.e. in spatial shaders and in the forward_plus or gl_compatibility renderers). </constant> <constant name="SOURCE_PORT" value="5" enum="Source"> Use the texture provided in the input port for this function. </constant> - <constant name="SOURCE_MAX" value="6" enum="Source"> + <constant name="SOURCE_3D_NORMAL" value="6" enum="Source"> + Use the normal buffer captured during the depth prepass. Only available when the normal-roughness buffer is available (i.e. in spatial shaders and in the forward_plus renderer). + </constant> + <constant name="SOURCE_ROUGHNESS" value="7" enum="Source"> + Use the roughness buffer captured during the depth prepass. Only available when the normal-roughness buffer is available (i.e. in spatial shaders and in the forward_plus renderer). + </constant> + <constant name="SOURCE_MAX" value="8" enum="Source"> Represents the size of the [enum Source] enum. </constant> <constant name="TYPE_DATA" value="0" enum="TextureType"> diff --git a/doc/classes/VisualShaderNodeTextureParameter.xml b/doc/classes/VisualShaderNodeTextureParameter.xml index 333226dc58..8a08bea659 100644 --- a/doc/classes/VisualShaderNodeTextureParameter.xml +++ b/doc/classes/VisualShaderNodeTextureParameter.xml @@ -18,6 +18,9 @@ <member name="texture_repeat" type="int" setter="set_texture_repeat" getter="get_texture_repeat" enum="VisualShaderNodeTextureParameter.TextureRepeat" default="0"> Sets the texture repeating mode. See [enum TextureRepeat] for options. </member> + <member name="texture_source" type="int" setter="set_texture_source" getter="get_texture_source" enum="VisualShaderNodeTextureParameter.TextureSource" default="0"> + Sets the texture source mode. Used for reading from the screen, depth, or normal_roughness texture. see [enum TextureSource] for options. + </member> <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureParameter.TextureType" default="0"> Defines the type of data provided by the source texture. See [enum TextureType] for options. </member> @@ -88,5 +91,20 @@ <constant name="REPEAT_MAX" value="3" enum="TextureRepeat"> Represents the size of the [enum TextureRepeat] enum. </constant> + <constant name="SOURCE_NONE" value="0" enum="TextureSource"> + The texture source is not specified in the shader. + </constant> + <constant name="SOURCE_SCREEN" value="1" enum="TextureSource"> + The texture source is the screen texture which captures all opaque objects drawn this frame. + </constant> + <constant name="SOURCE_DEPTH" value="2" enum="TextureSource"> + The texture source is the depth texture from the depth prepass. + </constant> + <constant name="SOURCE_NORMAL_ROUGHNESS" value="3" enum="TextureSource"> + The texture source is the normal-roughness buffer from the depth prepass. + </constant> + <constant name="SOURCE_MAX" value="4" enum="TextureSource"> + Represents the size of the [enum TextureSource] enum. + </constant> </constants> </class> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index dd145c016c..c4ea11ab66 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -729,6 +729,7 @@ [b]Note:[/b] This flag is implemented on macOS. </constant> <constant name="FLAG_MOUSE_PASSTHROUGH" value="7" enum="Flags"> + All mouse events are passed to the underlying window of the same application. </constant> <constant name="FLAG_MAX" value="8" enum="Flags"> Max value of the [enum Flags]. @@ -770,8 +771,16 @@ Right-to-left layout direction. </constant> <constant name="WINDOW_INITIAL_POSITION_ABSOLUTE" value="0" enum="WindowInitialPosition"> + Initial window position is determined by [member position]. </constant> - <constant name="WINDOW_INITIAL_POSITION_CENTER_SCREEN" value="1" enum="WindowInitialPosition"> + <constant name="WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN" value="1" enum="WindowInitialPosition"> + Initial window position is a center of the primary screen. + </constant> + <constant name="WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN" value="2" enum="WindowInitialPosition"> + Initial window position is a center of the main window screen. + </constant> + <constant name="WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN" value="3" enum="WindowInitialPosition"> + Initial window position is a center of [member current_screen] screen. </constant> </constants> <theme_items> diff --git a/doc/translations/ar.po b/doc/translations/ar.po index 751017b573..eb8e6dc7b6 100644 --- a/doc/translations/ar.po +++ b/doc/translations/ar.po @@ -30107,7 +30107,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/ca.po b/doc/translations/ca.po index 1552c15271..cce60f13ac 100644 --- a/doc/translations/ca.po +++ b/doc/translations/ca.po @@ -30023,7 +30023,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot index 40ab5e3413..3c793335e2 100644 --- a/doc/translations/classes.pot +++ b/doc/translations/classes.pot @@ -1,6 +1,6 @@ # LANGUAGE translation of the Godot Engine class reference. -# Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. -# Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). +# Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). +# Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. # This file is distributed under the same license as the Godot source code. # # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. @@ -29900,7 +29900,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/cs.po b/doc/translations/cs.po index 1bd920e19b..b2072217a1 100644 --- a/doc/translations/cs.po +++ b/doc/translations/cs.po @@ -30498,7 +30498,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/de.po b/doc/translations/de.po index 1533aa651d..14d2291f8c 100644 --- a/doc/translations/de.po +++ b/doc/translations/de.po @@ -33701,7 +33701,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/el.po b/doc/translations/el.po index 13c4fbfe68..63ddea8f7b 100644 --- a/doc/translations/el.po +++ b/doc/translations/el.po @@ -29951,7 +29951,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/es.po b/doc/translations/es.po index 8ed223238d..9462004570 100644 --- a/doc/translations/es.po +++ b/doc/translations/es.po @@ -39,12 +39,13 @@ # Keyla Arroyos <keylaarroyos@protonmail.com>, 2022. # Victor Stancioiu <victorstancioiu@gmail.com>, 2022. # yohanger <yohangerariel@gmail.com>, 2022. +# Mateo <mfdez920@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-11-29 20:23+0000\n" -"Last-Translator: yohanger <yohangerariel@gmail.com>\n" +"PO-Revision-Date: 2023-01-12 06:06+0000\n" +"Last-Translator: Mateo <mfdez920@gmail.com>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/" "godot-class-reference/es/>\n" "Language: es\n" @@ -52,7 +53,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -751,7 +752,6 @@ msgstr "" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns an array of dictionaries representing the current call stack. See " "also [method print_stack].\n" @@ -776,7 +776,7 @@ msgid "" "projects exported in debug mode if not connected to a debugging server." msgstr "" "Devuelve un conjunto de diccionarios que representan la pila de llamadas " -"actual.\n" +"actual. Véase también [method print_stack].\n" "[codeblock]\n" "func _ready():\n" " foo()\n" @@ -39560,6 +39560,7 @@ msgid "" msgstr "" #: doc/classes/Input.xml +#, fuzzy msgid "" "Sets a custom mouse cursor image, which is only visible inside the game " "window. The hotspot can also be specified. Passing [code]null[/code] to the " @@ -39571,7 +39572,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" "Establece una imagen personalizada del cursor del ratón, que sólo es visible " "dentro de la ventana del juego. También se puede especificar el punto de " diff --git a/doc/translations/et.po b/doc/translations/et.po index 7f92671d8f..b7512b6ae5 100644 --- a/doc/translations/et.po +++ b/doc/translations/et.po @@ -29913,7 +29913,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/fa.po b/doc/translations/fa.po index 787c7ff937..ce5dd6b0c2 100644 --- a/doc/translations/fa.po +++ b/doc/translations/fa.po @@ -30352,7 +30352,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/fi.po b/doc/translations/fi.po index fc517a6ff5..0f19296424 100644 --- a/doc/translations/fi.po +++ b/doc/translations/fi.po @@ -30034,7 +30034,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/fil.po b/doc/translations/fil.po index 749fea9ef9..bfa8c75c7a 100644 --- a/doc/translations/fil.po +++ b/doc/translations/fil.po @@ -29919,7 +29919,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/fr.po b/doc/translations/fr.po index 2898e9ec19..a57c138429 100644 --- a/doc/translations/fr.po +++ b/doc/translations/fr.po @@ -60,13 +60,14 @@ # Augustin Ambiehl <ambiehlaugustin@gmail.com>, 2022. # Landry Simo <landrysimo99@gmail.com>, 2022. # Alexis Coudert <coudert.alex@gmail.com>, 2022. +# Callim Ethee <callimethee@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-12-03 00:47+0000\n" -"Last-Translator: Alexis Coudert <coudert.alex@gmail.com>\n" +"PO-Revision-Date: 2023-01-01 02:51+0000\n" +"Last-Translator: Callim Ethee <callimethee@gmail.com>\n" "Language-Team: French <https://hosted.weblate.org/projects/godot-engine/" "godot-class-reference/fr/>\n" "Language: fr\n" @@ -74,7 +75,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -137,9 +138,8 @@ msgid "Default" msgstr "Défaut" #: doc/tools/make_rst.py -#, fuzzy msgid "Setter" -msgstr "Setter" +msgstr "Donneur" #: doc/tools/make_rst.py msgid "value" @@ -39456,7 +39456,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/gl.po b/doc/translations/gl.po index 67bd7d902f..9b3ea41370 100644 --- a/doc/translations/gl.po +++ b/doc/translations/gl.po @@ -29908,7 +29908,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/hi.po b/doc/translations/hi.po index 75318a4554..ca1ba04874 100644 --- a/doc/translations/hi.po +++ b/doc/translations/hi.po @@ -29907,7 +29907,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/hu.po b/doc/translations/hu.po index e99babd548..f5a053dfc9 100644 --- a/doc/translations/hu.po +++ b/doc/translations/hu.po @@ -29927,7 +29927,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/id.po b/doc/translations/id.po index ad63a828e5..8a1e757105 100644 --- a/doc/translations/id.po +++ b/doc/translations/id.po @@ -30324,7 +30324,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/is.po b/doc/translations/is.po index 6bf49858f4..0afd2be589 100644 --- a/doc/translations/is.po +++ b/doc/translations/is.po @@ -29907,7 +29907,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/it.po b/doc/translations/it.po index 37488c9ebd..35ff1ac6f3 100644 --- a/doc/translations/it.po +++ b/doc/translations/it.po @@ -31127,7 +31127,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/ja.po b/doc/translations/ja.po index cabf1da54a..2798995dfa 100644 --- a/doc/translations/ja.po +++ b/doc/translations/ja.po @@ -33191,7 +33191,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/ko.po b/doc/translations/ko.po index 72a7780a4c..3b3137f849 100644 --- a/doc/translations/ko.po +++ b/doc/translations/ko.po @@ -19,12 +19,13 @@ # ì´ì§€ë¯¼ <jiminaleejung@gmail.com>, 2022. # nulltable <un5450@naver.com>, 2022. # Godoto <aicompose@gmail.com>, 2022. +# 오지훈 <jule1130@naver.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-10-18 18:00+0000\n" -"Last-Translator: Godoto <aicompose@gmail.com>\n" +"PO-Revision-Date: 2023-01-19 14:47+0000\n" +"Last-Translator: 오지훈 <jule1130@naver.com>\n" "Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/" "godot-class-reference/ko/>\n" "Language: ko\n" @@ -32,11 +33,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1\n" #: doc/tools/make_rst.py msgid "Description" -msgstr "ì„œìˆ " +msgstr "설명" #: doc/tools/make_rst.py msgid "Tutorials" @@ -30234,7 +30235,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/lt.po b/doc/translations/lt.po index 1cf0ffef48..c52d238af9 100644 --- a/doc/translations/lt.po +++ b/doc/translations/lt.po @@ -29917,7 +29917,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/lv.po b/doc/translations/lv.po index fd9ddf6f51..bf5aa78341 100644 --- a/doc/translations/lv.po +++ b/doc/translations/lv.po @@ -29925,7 +29925,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/mr.po b/doc/translations/mr.po index 19db2e5f94..71013cc0e7 100644 --- a/doc/translations/mr.po +++ b/doc/translations/mr.po @@ -29905,7 +29905,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/nb.po b/doc/translations/nb.po index 3b7f482e48..6431d1756d 100644 --- a/doc/translations/nb.po +++ b/doc/translations/nb.po @@ -29917,7 +29917,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/ne.po b/doc/translations/ne.po index c616f7b4e1..b043d7c5af 100644 --- a/doc/translations/ne.po +++ b/doc/translations/ne.po @@ -29905,7 +29905,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/nl.po b/doc/translations/nl.po index cf40d032cf..de3a4a7497 100644 --- a/doc/translations/nl.po +++ b/doc/translations/nl.po @@ -29978,7 +29978,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/pl.po b/doc/translations/pl.po index cd2bedd302..a5c59f489b 100644 --- a/doc/translations/pl.po +++ b/doc/translations/pl.po @@ -30529,7 +30529,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/pt.po b/doc/translations/pt.po index d3d9b9aadf..0f7b9f54e3 100644 --- a/doc/translations/pt.po +++ b/doc/translations/pt.po @@ -4,7 +4,7 @@ # This file is distributed under the same license as the Godot source code. # # Reubens Sanders <reubensst@protonmail.com>, 2021. -# ssantos <ssantos@web.de>, 2022. +# ssantos <ssantos@web.de>, 2022, 2023. # Felipe SiFa <felipe@logus.digital>, 2022. # Renu <ifpilucas@gmail.com>, 2022. # Diogo Gomes <dgomes@graphnode.com>, 2022. @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-11-18 16:48+0000\n" +"PO-Revision-Date: 2023-01-11 16:51+0000\n" "Last-Translator: ssantos <ssantos@web.de>\n" "Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/" "godot-class-reference/pt/>\n" @@ -27,7 +27,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -394,8 +394,8 @@ msgid "" "[/codeblock]\n" "This is the inverse of [method ord]." msgstr "" -"Retorna um caractere como uma String de um dado code point Unicode (que é " -"compatÃvel com ASCII code);\n" +"Retorna um caractere como uma cadeia de caracteres de um dado code point " +"Unicode (compatÃvel com ASCII code);\n" "[codeblock]\n" "a = char(65) # a é \"A\"\n" "a = char(65 + 32) # a é \"a\"\n" @@ -517,15 +517,15 @@ msgid "" "want a true content-aware comparison, you have to use [code]deep_equal[/" "code]." msgstr "" -"Compara dois valores verificando seu conteúdo real, por meio de recursão em " -"um [Array] ou [Dictionary] em todos os seus nÃveis.\n" -"Esta função se asemelha ou difere de [code]==[/code] de diversas maneiras:\n" +"Compara dois valores verificando o conteúdo real deles, por meio de recursão " +"em um [Array] ou [Dictionary] em todos os seus nÃveis.\n" +"Esta função compara a [code]==[/code] de diversas maneiras:\n" "- Para [code]null[/code], [code]int[/code], [code]float[/code], " "[code]String[/code], [code]Object[/code] e [code] RID[/code] tanto " "[code]deep_equal[/code] quanto [code]==[/code] funcionam da mesma forma.\n" "- Para [code]Dictionary[/code], [code]==[/code] considera-se igual se, e " "somente se, ambas as variáveis apontarem para o mesmo [code]Dictionary[/" -"code], sem recursão ou checagem de seu conteúdo.\n" +"code], sem recursão ou checagem do seu conteúdo.\n" "- Para [code]Array[/code], [code]==[/code] considera igual se, e somente se, " "cada item no primeiro [code]Array[/code] for igual ao seu homólogo no " "segundo [ code]Array[/code], conforme informado pelo próprio [code]==[/" @@ -928,7 +928,7 @@ msgid "" "[/codeblock]" msgstr "" "Retorna o comprimento da Variant [code]var[/code]. Comprimento é a contagem " -"de caracteres de uma String, contagem de elementos de uma Array, o tamanho " +"de caracteres de uma cadeia, contagem de elementos de uma Array, o tamanho " "de um Dicionario, etc.\n" "[b]Note:[/b] Gera um erro fatal se Variant não puder retornar um " "comprimento.\n" @@ -1361,7 +1361,7 @@ msgid "" "distinguishes them from print messages used for debugging purposes, while " "also displaying a stack trace when an error or warning is printed." msgstr "" -"Converte um ou mais argumentos de qualquer tipo para string da melhor " +"Converte um ou mais argumentos de qualquer tipo para cadeia da melhor " "maneira possÃvel e imprime no console\n" "[codeblock]\n" "a = [1, 2, 3]\n" @@ -1370,7 +1370,7 @@ msgstr "" "[b]Nota:[/b] Considere usar [method push_error] e [method push_warning] para " "imprimir mensagens de erro e aviso ao invés de [method print]. Isso os " "distinguirá de impressões com propósito de depuração e também mostrará um " -"rastreamento de pilha quando um erro ou aviso é impresso ." +"rastreamento de pilha quando um erro ou aviso é impresso." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1890,7 +1890,7 @@ msgid "" "len(b) # Returns 12\n" "[/codeblock]" msgstr "" -"Converte um ou mais argumentos de quaisquer tipos para string na melhor " +"Converte um ou mais argumentos de quaisquer tipos para cadeia na melhor " "maneira possÃvel.\n" "[codeblock]\n" "var a = [10, 20, 30]\n" @@ -1909,7 +1909,7 @@ msgid "" "print(b[\"a\"]) # Prints 1\n" "[/codeblock]" msgstr "" -"Converte um string formatado que foi retornado por [method var2str] para o " +"Converte uma cadeia formatada que foi retornada por [method var2str] para o " "valor original.\n" "[codeblock]\n" "a = '{ \"a\": 1, \"b\": 2 }'\n" @@ -2025,8 +2025,8 @@ msgid "" " push_error(\"Invalid JSON: \" + v)\n" "[/codeblock]" msgstr "" -"Verifica se [code]json[/code] contém dados JSON válidos. Retorna um String " -"vazio se válido, ou uma mensagem de erro caso contrário.\n" +"Verifica se [code]json[/code] contém dados JSON válidos. Retorna uma cadeia " +"vazia se for válida ou uma mensagem de erro caso contrário.\n" "[codeblock]\n" "j = to_json([1, 2, 3])\n" "v = validate_json(j)\n" @@ -2062,8 +2062,8 @@ msgid "" "}\n" "[/codeblock]" msgstr "" -"Converte uma Variant [code]var[/code] para um string formatado que pode ser " -"convertido de volta com [method str2var].\n" +"Converte uma Variant [code]var[/code] para uma cadeia formatada que pode ser " +"convertida de volta com [method str2var].\n" "[codeblock]\n" "a = { \"a\": 1, \"b\": 2 }\n" "print(var2str(a))\n" @@ -3555,59 +3555,59 @@ msgstr "Máscara da tecla Group Switch." #: doc/classes/@GlobalScope.xml msgid "Left mouse button." -msgstr "Botão esquerdo do mouse." +msgstr "Botão esquerdo do rato." #: doc/classes/@GlobalScope.xml msgid "Right mouse button." -msgstr "Botão direito do mouse." +msgstr "Botão direito do rato." #: doc/classes/@GlobalScope.xml msgid "Middle mouse button." -msgstr "Botão central do mouse." +msgstr "Botão central do rato." #: doc/classes/@GlobalScope.xml msgid "Extra mouse button 1 (only present on some mice)." -msgstr "Primeiro botão extra do mouse (disponÃvel em apenas alguns mouses)." +msgstr "Primeiro botão extra do rato (disponÃvel em apenas alguns ratos)." #: doc/classes/@GlobalScope.xml msgid "Extra mouse button 2 (only present on some mice)." -msgstr "Segundo botão extra do mouse (disponÃvel em apenas alguns mouses)." +msgstr "Segundo botão extra do rato (disponÃvel em apenas alguns ratos)." #: doc/classes/@GlobalScope.xml msgid "Mouse wheel up." -msgstr "Roda do mouse para cima." +msgstr "Roda do rato para cima." #: doc/classes/@GlobalScope.xml msgid "Mouse wheel down." -msgstr "Roda do mouse para baixo." +msgstr "Roda do rato para baixo." #: doc/classes/@GlobalScope.xml msgid "Mouse wheel left button (only present on some mice)." -msgstr "Botão esquerdo da roda do mouse (disponÃvel em apenas alguns mouses)." +msgstr "Botão esquerdo da roda do rato (disponÃvel em apenas alguns ratos)." #: doc/classes/@GlobalScope.xml msgid "Mouse wheel right button (only present on some mice)." -msgstr "Botão direito da roda do mouse (disponÃvel em apenas alguns mouses)." +msgstr "Botão direito da roda do rato (disponÃvel em apenas alguns ratos)." #: doc/classes/@GlobalScope.xml msgid "Left mouse button mask." -msgstr "Máscara do botão esquerdo do mouse." +msgstr "Máscara do botão esquerdo do rato." #: doc/classes/@GlobalScope.xml msgid "Right mouse button mask." -msgstr "Máscara do botão direito do mouse." +msgstr "Máscara do botão direito do rato." #: doc/classes/@GlobalScope.xml msgid "Middle mouse button mask." -msgstr "Máscara do botão central do mouse." +msgstr "Máscara do botão central do rato." #: doc/classes/@GlobalScope.xml msgid "Extra mouse button 1 mask." -msgstr "Máscara do primeiro botão extra do mouse." +msgstr "Máscara do primeiro botão extra do rato." #: doc/classes/@GlobalScope.xml msgid "Extra mouse button 2 mask." -msgstr "Máscara do segundo botão extra do mouse." +msgstr "Máscara do segundo botão extra do rato." #: doc/classes/@GlobalScope.xml msgid "Invalid button or axis." @@ -4354,7 +4354,6 @@ msgid "" msgstr "" #: doc/classes/@GlobalScope.xml -#, fuzzy msgid "" "Hints that a float property should be edited via an exponential easing " "function. The hint string can include [code]\"attenuation\"[/code] to flip " @@ -4362,9 +4361,9 @@ msgid "" "easing." msgstr "" "Sugere que uma propriedade float deve ser editada através de uma função de " -"suavização. A string de sugestão pode incluir [code]\"attenuation\"[/code] " -"para virar a curva horizontalmente e/ou [code]\"inout\"[/code] para incluir " -"também a suavização in/out." +"flexibilização. A cadeia de sugestão pode incluir [code]\"attenuation\"[/" +"code] para virar a curva horizontalmente e/ou [code]\"inout\"[/code] para " +"incluir também a flexibilização in/out." #: doc/classes/@GlobalScope.xml msgid "Deprecated hint, unused." @@ -17844,11 +17843,11 @@ msgstr "" #: doc/classes/Control.xml msgid "Sent when the mouse pointer enters the node." -msgstr "Enviado quando o ponteiro do mouse entra no nó." +msgstr "Enviado quando o ponteiro do rato entra no nó." #: doc/classes/Control.xml msgid "Sent when the mouse pointer exits the node." -msgstr "Enviado quando o ponteiro do mouse sai do nó." +msgstr "Enviado quando o ponteiro do rato sai do nó." #: doc/classes/Control.xml msgid "Sent when the node grabs focus." @@ -30979,7 +30978,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml @@ -37028,7 +37031,7 @@ msgstr "" #: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml #, fuzzy msgid "Sets the position of the agent in world space." -msgstr "Retorna a posição global do mouse." +msgstr "Retorna a posição global do rato." #: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml #, fuzzy @@ -37256,7 +37259,7 @@ msgstr "" #: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml #, fuzzy msgid "Sets the global transformation for the region." -msgstr "Retorna a posição global do mouse." +msgstr "Retorna a posição global do rato." #: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml #, fuzzy @@ -65291,11 +65294,11 @@ msgstr "Emitido quando um item é editado." #: doc/classes/Tree.xml msgid "Emitted when an item is edited using the right mouse button." -msgstr "Emitido quando um item é editado com botão direito do mouse." +msgstr "Emitido quando um item é editado com botão direito do rato." #: doc/classes/Tree.xml msgid "Emitted when an item is selected with the right mouse button." -msgstr "Emitido quando um item é selecionado com o botão direito do mouse." +msgstr "Emitido quando um item é selecionado com o botão direito do rato." #: doc/classes/Tree.xml msgid "Emitted when an item is selected." @@ -65310,7 +65313,7 @@ msgstr "" #: doc/classes/Tree.xml msgid "Emitted when a left mouse button click does not select any item." msgstr "" -"Emitido quando um clique com o botão esquerdo do mouse não seleciona nenhum " +"Emitido quando um clique com o botão esquerdo do rato não seleciona nenhum " "item." #: doc/classes/Tree.xml diff --git a/doc/translations/pt_BR.po b/doc/translations/pt_BR.po index 463bc9c957..687566bef1 100644 --- a/doc/translations/pt_BR.po +++ b/doc/translations/pt_BR.po @@ -45,12 +45,13 @@ # Mr.Albino <ricmorsoleto@gmail.com>, 2022. # Zer0-Zer0 <dankmemerson@tutanota.com>, 2022. # Julio Yagami <juliohenrique31501234@hotmail.com>, 2022. +# Andrey Gonçalves <kaptaryd@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-12-09 19:48+0000\n" -"Last-Translator: Julio Yagami <juliohenrique31501234@hotmail.com>\n" +"PO-Revision-Date: 2023-01-09 20:42+0000\n" +"Last-Translator: Andrey Gonçalves <kaptaryd@gmail.com>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "godot-engine/godot-class-reference/pt_BR/>\n" "Language: pt_BR\n" @@ -58,7 +59,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -860,7 +861,6 @@ msgstr "" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns an interpolation or extrapolation factor considering the range " "specified in [code]from[/code] and [code]to[/code], and the interpolated " @@ -883,8 +883,26 @@ msgid "" "See also [method lerp] which performs the reverse of this operation, and " "[method range_lerp] to map a continuous series of values to another." msgstr "" -"Retornar a interpolação ou extrapolação do fator considerando o ranger " -"especÃfico [code ]para[/code]" +"Retorna o fator de interpolação ou extrapolação considerando o intervalo " +"especificado no [code]de[/code] e [code]para[/code], e o valor interpolado " +"especificado no [code]peso[/code]. O valor retornado irá ser entre " +"[code]0.0[/code] e [code]1.0[/code] se [code]peso[/code] for entre [code]de[/" +"code] e [code]para[/code] (inclusivo). Se [code]peso[/code] está fora do " +"intervalo especificado, então um fator de extrapolação será retornado " +"(retorna valor menor que [code]0.0[/code] ou maior que [code]1.0[/code]). " +"Use [method clamp] no resultado do [method inverse_lerp] se isso não for o " +"desejado.\n" +"[codeblock]\n" +"# A razão da interpolação no uso do `lerp()` abaixo é 0.75.\n" +"var meio = lerp(20, 30, 0.75)\n" +"#`meio` agora é 27.5.\n" +"# Agora, vamos fingir que esquecemos a razão original e o queremos de " +"volta.\n" +"var razao = inverse_lerp(20, 30, 27.5)\n" +"#`razao` agora é 0.75.\n" +"[/codeblock]\n" +"Veja também o [method lerp] que faz o inverso desta operação, e [method " +"range_lerp] para mapear uma série contÃnua de valores uns aos outros." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1423,6 +1441,17 @@ msgid "" "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." msgstr "" +"Imprime um rastreamento de pilha no local do código atual. Veja também " +"[method get_stack]\n" +"A saÃda no console seria mais ou menos assim:\n" +"[codeblock]\n" +"Frame 0 - res://test.gd:16 in function '_process'\n" +"[/codeblock]\n" +"[b]Nota:[/b] [method print_stack] só funciona se a instância em execução " +"estiver conectada a um servidor de depuração (ou seja, uma instância do " +"editor). [method print_stack] não funcionará em projetos exportados no modo " +"de lançamento ou em projetos exportados no modo de depuração se não estiver " +"conectado a um servidor de depuração." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -4070,74 +4099,105 @@ msgid "" "down on the key after it \"bottoms out\". This message is different from " "polyphonic after-touch as it indicates the highest pressure across all keys." msgstr "" +"Mensagem de pressão do canal MIDI. Esta mensagem geralmente é enviada ao " +"pressionar a tecla após ela \"ir de dentro pra fora\". Essa mensagem é " +"diferente do pós-toque polifônico, pois indica a pressão mais alta em todas " +"as teclas." #: doc/classes/@GlobalScope.xml msgid "" "MIDI pitch bend message. This message is sent to indicate a change in the " "pitch bender (wheel or lever, typically)." msgstr "" +"Mensagem MIDI de dobra de tom (pitch bend). Esta mensagem é enviada para " +"indicar uma mudança no dobrador de tom (roda ou alavanca, tipicamente)." #: doc/classes/@GlobalScope.xml msgid "" "MIDI system exclusive message. This has behavior exclusive to the device " "you're receiving input from. Getting this data is not implemented in Godot." msgstr "" +"Mensagem exclusiva do sistema MIDI. Isso tem um comportamento exclusivo do " +"dispositivo do qual você está recebendo entrada. A obtenção desses dados não " +"está implementada no Godot." #: doc/classes/@GlobalScope.xml msgid "" "MIDI quarter frame message. Contains timing information that is used to " "synchronize MIDI devices. Getting this data is not implemented in Godot." msgstr "" +"Mensagem MIDI de um quarto de quadro. Contém informações de tempo usadas " +"para sincronizar dispositivos MIDI. A obtenção desses dados não está " +"implementada no Godot." #: doc/classes/@GlobalScope.xml msgid "" "MIDI song position pointer message. Gives the number of 16th notes since the " "start of the song. Getting this data is not implemented in Godot." msgstr "" +"Mensagem de ponteiro de posição de música MIDI. Dá o número de semicolcheias " +"(cada 16ª nota) desde o inÃcio da música. A obtenção desses dados não está " +"implementada no Godot." #: doc/classes/@GlobalScope.xml msgid "" "MIDI song select message. Specifies which sequence or song is to be played. " "Getting this data is not implemented in Godot." msgstr "" +"Mensagem MIDI de seleção de música. Especifica qual sequência ou música será " +"tocada. A obtenção desses dados não está implementada no Godot." #: doc/classes/@GlobalScope.xml msgid "" "MIDI tune request message. Upon receiving a tune request, all analog " "synthesizers should tune their oscillators." msgstr "" +"Mensagem de solicitação de sintonia MIDI. Ao receber uma solicitação de " +"sintonia, todos os sintetizadores analógicos devem sintonizar seus " +"osciladores." #: doc/classes/@GlobalScope.xml msgid "" "MIDI timing clock message. Sent 24 times per quarter note when " "synchronization is required." msgstr "" +"Mensagem de relógio de tempo MIDI. Enviado 24 vezes por semÃnima quando a " +"sincronização é necessária." #: doc/classes/@GlobalScope.xml msgid "" "MIDI start message. Start the current sequence playing. This message will be " "followed with Timing Clocks." msgstr "" +"mensagem de inÃcio MIDI. Inicie a reprodução da sequência atual. Esta " +"mensagem será seguida de relógios de temporização." #: doc/classes/@GlobalScope.xml msgid "MIDI continue message. Continue at the point the sequence was stopped." msgstr "" +"Mensagem de continuação MIDI. Continue no ponto em que a sequência foi " +"interrompida." #: doc/classes/@GlobalScope.xml msgid "MIDI stop message. Stop the current sequence." -msgstr "" +msgstr "Mensagem de parada MIDI. Pare a sequência atual." #: doc/classes/@GlobalScope.xml msgid "" "MIDI active sensing message. This message is intended to be sent repeatedly " "to tell the receiver that a connection is alive." msgstr "" +"Mensagem de detecção ativa de MIDI. Esta mensagem deve ser enviada " +"repetidamente para informar ao receptor que uma conexão está ativa." #: doc/classes/@GlobalScope.xml msgid "" "MIDI system reset message. Reset all receivers in the system to power-up " "status. It should not be sent on power-up itself." msgstr "" +"Mensagem de reinicialização do sistema MIDI. Redefina todos os receptores no " +"sistema para o status de inicialização. Ele não deve ser enviado no próprio " +"power-up." #: doc/classes/@GlobalScope.xml msgid "" @@ -31205,7 +31265,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/ro.po b/doc/translations/ro.po index dd88e8d66b..94c966c61c 100644 --- a/doc/translations/ro.po +++ b/doc/translations/ro.po @@ -29940,7 +29940,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/ru.po b/doc/translations/ru.po index 9d569d7760..b76873e4f1 100644 --- a/doc/translations/ru.po +++ b/doc/translations/ru.po @@ -57,12 +57,14 @@ # Handsless coder <yfintktajy1@gmail.com>, 2022. # Evgeniy Khramov <thejenjagamertjg@gmail.com>, 2022. # Григорий <bolon667@gmail.com>, 2022. +# Artur Leonov (Depish) <depish.eskry@yandex.ru>, 2022. +# Patrik <avdmur@gmail.com>, 2022. msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-12-06 11:48+0000\n" -"Last-Translator: Григорий <bolon667@gmail.com>\n" +"PO-Revision-Date: 2022-12-23 10:00+0000\n" +"Last-Translator: Patrik <avdmur@gmail.com>\n" "Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/" "godot-class-reference/ru/>\n" "Language: ru\n" @@ -71,7 +73,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -127,7 +129,7 @@ msgstr "УнаÑледовано:" #: doc/tools/make_rst.py msgid "(overrides %s)" -msgstr "(переназначает %s)" +msgstr "(переопределÑет %s)" #: doc/tools/make_rst.py msgid "Default" @@ -461,9 +463,9 @@ msgstr "" "Ограничивает [code]value[/code], Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ не меньше [code]min[/" "code] и не больше [code]max[/code].\n" "[codeblock]\n" -"a = clamp(1000, 1, 20) # a будет 20\n" -"a = clamp(-10, 1, 20) # a будет 1\n" -"a = clamp(15, 1, 20) # a будет 15\n" +"a = clamp(1000, 1, 20) # вернёт 20\n" +"a = clamp(-10, 1, 20) # вернёт 1\n" +"a = clamp(15, 1, 20) # вернёт 15\n" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml @@ -534,12 +536,12 @@ msgid "" "a = dectime(60, 10, 0.1)) # a is 59.0\n" "[/codeblock]" msgstr "" -"[b]Примечание:[/b] [code]dectime[/code] был уÑтаревшим и будет удален в " -"Godot 4.0, пожалуйÑта, иÑпользуйте [метод move_toward] вмеÑто него.\n" +"[b]Примечание:[/b] [code]dectime[/code] уÑтарел и будет удален в Godot 4.0, " +"пожалуйÑта, иÑпользуйте [method move_toward] вмеÑто него.\n" "Возвращает результат [code]value[/code], уменьшенный на [code]step[/code] * " "[code]amount[/code].\n" "[codeblock]\n" -"a = dectime(60, 10, 0.1)) # a равно 59.0\n" +"a = dectime(60, 10, 0.1)) # вернёт59.0\n" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml @@ -635,7 +637,7 @@ msgstr "" "[/codeblock]\n" "[url=https://raw.githubusercontent.com/godotengine/godot-docs/3.4/img/" "ease_cheatsheet.png]ease() шпаргалка значений кривой[/url]\n" -"См. также [метод smoothstep]. ЕÑли вам нужно выполнить более Ñложные " +"См. также [method smoothstep]. ЕÑли вам нужно выполнить более Ñложные " "переходы, иÑпользуйте [Tween] или [AnimationPlayer]." #: modules/gdscript/doc_classes/@GDScript.xml @@ -766,7 +768,6 @@ msgstr "" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns an array of dictionaries representing the current call stack. See " "also [method print_stack].\n" @@ -790,22 +791,27 @@ msgid "" "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." msgstr "" -"Возвращает маÑÑив Ñловарей, предÑтавлÑющий текущий Ñтек вызовов.\n" +"Возвращает маÑÑив Ñловарей, предÑтавлÑющий текущий Ñтек вызовов. См. также " +"[method print_stack].\n" "[codeblock]\n" "func _ready():\n" -" foo()\n" +"\tfoo()\n" "\n" "func foo():\n" -" bar()\n" +"\tbar()\n" "\n" "func bar():\n" -" print(get_stack())\n" +"\tprint(get_stack())\n" "[/codeblock]\n" "выведет\n" "[codeblock]\n" "[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, " "source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]\n" -"[/codeblock]" +"[/codeblock]\n" +"[b]Примечание:[/b] [method get_stack] работает только при подключенном " +"Ñервере отладки (например в редакторе). [method get_stack] не будет работать " +"в проектах, ÑкÑпортированных в режиме release или в проектах " +"ÑкÑпортированных в режиме debug, еÑли они не подключены к Ñерверу отладки." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -914,7 +920,8 @@ msgstr "" "var ratio = inverse_lerp(20, 30, 27.5)\n" "# `ratio` теперь 0.75.\n" "[/codeblock]\n" -"Смотрите также [метод lerp], который выполнÑет обратную Ñтой операцию." +"Смотрите также [method lerp], который выполнÑет обратную операцию и [method " +"range_lerp] Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледовательного Ñ€Ñда значений в другом." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1048,23 +1055,23 @@ msgid "" msgstr "" "Ð›Ð¸Ð½ÐµÐ¹Ð½Ð°Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»ÑÑ†Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ Ð´Ð²ÑƒÐ¼Ñ ÑƒÐ³Ð»Ð°Ð¼Ð¸ (в радианах) по нормализованному " "значению.\n" -"Ðналогично [методу lerp], но корректно интерполируетÑÑ, когда углы " -"оборачивают вокруг [конÑтанты @GDScript.TAU]. Чтобы выполнить упрощенную " -"интерполÑцию Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [метода lerp_angle], объедините его Ñ [методом ease] " -"или [методом smoothstep].\n" +"Ðналогично [method lerp], но корректно интерполируетÑÑ, когда углы " +"оборачивают вокруг [constant @GDScript.TAU]. Чтобы выполнить упрощенную " +"интерполÑцию Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [method lerp_angle], объедините его Ñ [method ease] " +"или [method smoothstep].\n" "[codeblock]\n" "extends Sprite\n" "var elapsed = 0.0\n" "func _process(delta):\n" -" var min_angle = deg2rad(0.0)\n" -" var max_angle = deg2rad(90.0)\n" -" rotation = lerp_angle(min_angle, max_angle, elapsed)\n" -" elapsed += delta\n" +"\tvar min_angle = deg2rad(0.0)\n" +"\tvar max_angle = deg2rad(90.0)\n" +"\trotation = lerp_angle(min_angle, max_angle, elapsed)\n" +"\telapsed += delta\n" "[/codeblock]\n" "[b]Примечание:[/b] Ðтот метод проходит через кратчайший путь между " "[code]from[/code] и [code]to[/code]. Тем не менее, еÑли разница между Ñтими " -"Ð´Ð²ÑƒÐ¼Ñ ÑƒÐ³Ð»Ð°Ð¼Ð¸ и любым целым чиÑлом [code]k[/code] приблизительно [code]PI + " -"k * TAU[/code], неочевидно в какую Ñторону [/code]из-за ошибок в точноÑти " +"Ð´Ð²ÑƒÐ¼Ñ ÑƒÐ³Ð»Ð°Ð¼Ð¸ и любым целым чиÑлом [code]k[/code] приблизительно [code]PI + k " +"* TAU[/code], неочевидно в какую Ñторону [/code]из-за ошибок в точноÑти " "чиÑел Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой. Ðапример, [code]lerp_angle(0, PI, weight)[/code] " "оборачиваетÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¸Ð² чаÑовой Ñтрелки, а [code]lerp_angle(0, PI + 5 * TAU, " "weight)[/code] оборачиваетÑÑ Ð¿Ð¾ чаÑовой." @@ -1098,6 +1105,7 @@ msgstr "" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml +#, fuzzy msgid "" "Loads a resource from the filesystem located at [code]path[/code]. The " "resource is loaded on the method call (unless it's referenced already " @@ -1124,19 +1132,19 @@ msgstr "" "ÑÑылаютÑÑ Ð² другом меÑте, например, в другом Ñкрипте или в Ñцене), что может " "вызвать небольшую задержку, оÑобенно при загрузке Ñцен. Чтобы избежать " "ненужных задержек при многократной загрузке чего-либо, либо Ñохраните реÑÑƒÑ€Ñ " -"в переменной, либо иÑпользуйте [метод preload].\n" +"в переменной, либо иÑпользуйте [method preload].\n" "[b]Примечание: [/b] Пути к реÑурÑам можно получить, щёлкнув правой кнопкой " "мыши на реÑурÑе в панели Â«Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема» и выбрав \"Копировать путь\" или " "перетащив файл из панели Â«Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема» в Ñценарий.\n" "[codeblock]\n" "# Load a scene called main located in the root of the project directory and " "cache it in a variable.\n" -"var main = load(\"res://main.tscn\") # main will contain a PackedScene " -"resource.\n" +"var main = load(\"res://main.tscn\") # main будет Ñодержать объект " +"PackedScene.\n" "[/codeblock]\n" "[b]Важно:[/b] Путь должен быть абÑолютным, локальный путь проÑто вернет " "[code]null[/code].\n" -"Ðтот метод предÑтавлÑет Ñобой упрощенную верÑию [метода ResourceLoader." +"Ðтот метод предÑтавлÑет Ñобой упрощенную верÑию [method ResourceLoader." "load], который можно иÑпользовать Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ Ñложных Ñценариев." #: modules/gdscript/doc_classes/@GDScript.xml @@ -1449,6 +1457,16 @@ msgid "" "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." msgstr "" +"Выводит Ñтек вызовов из текущей функции. Смотрите также: [method " +"get_stack].\n" +"Вывод в конÑоли будет примерно таким:\n" +"[codeblock]\n" +"Frame 0 - res://test.gd:16 in function '_process'\n" +"[/codeblock]\n" +"[b]Примечание:[/b] [method print_stack] работает только при подключенном " +"Ñервере отладки (например в редакторе). [method print_stack] не будет " +"работать в проектах, ÑкÑпортированных в режиме release или в проектах " +"ÑкÑпортированных в режиме debug, еÑли они не подключены к Ñерверу отладки." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1687,7 +1705,7 @@ msgid "" "3\n" "[/codeblock]" msgstr "" -"Возвращает маÑÑив Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ диапазоном. [метод range] может быть вызван " +"Возвращает маÑÑив Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ диапазоном. [method range] может быть вызван " "Ñ‚Ñ€ÐµÐ¼Ñ ÑпоÑобами:\n" "[code]range(n: int)[/code]: ÐачинаетÑÑ Ñ 0, увеличиваетÑÑ Ñ ÑˆÐ°Ð³Ð¾Ð¼ в 1 и " "оÑтанавливаетÑÑ [i]перед[/i] [code]n[/code]. Ðргумент [code]n[/code] Ñто " @@ -1702,16 +1720,16 @@ msgstr "" "[b]инклюзив[/b] и [b]ÑкÑклюзив[/b], ÑоответÑтвенно. Ðргумент [code]s[/code] " "[b]может[/b] быть негативным, но не [code]0[/code]. ЕÑли [code]s[/code] Ñто " "[code]0[/code], будет выведено Ñообщение об ошибке.\n" -"[метод range] преобразует вÑе аргументы в [int] перед обработкой.\n" +"[method range] преобразует вÑе аргументы в [int] перед обработкой.\n" "[b]Примечание:[/b] Возвращает пуÑтой маÑÑив, еÑли ни одно значение не " "удовлетворÑет ограничению на значение (e.g. [code]range(2, 5, -1)[/code] или " "[code]range(5, 5, 1)[/code]).\n" "Примеры:\n" "[codeblock]\n" -"print(range(4)) # Prints [0, 1, 2, 3]\n" -"print(range(2, 5)) # Prints [2, 3, 4]\n" -"print(range(0, 6, 2)) # Prints [0, 2, 4]\n" -"print(range(4, 1, -1)) # Prints [4, 3, 2]\n" +"print(range(4)) # Выведет [0, 1, 2, 3]\n" +"print(range(2, 5)) # Выведет [2, 3, 4]\n" +"print(range(0, 6, 2)) # Выведет [0, 2, 4]\n" +"print(range(4, 1, -1)) # Выведет [4, 3, 2]\n" "[/codeblock]\n" "Чтобы выполнить итерацию по [Array] в обратном порÑдке, иÑпользуйте:\n" "[codeblock]\n" @@ -1739,6 +1757,18 @@ msgid "" "For complex use cases where you need multiple ranges, consider using [Curve] " "or [Gradient] instead." msgstr "" +"Ограничивает [code]значение[/code] из диапазона [code][istart, istop][/code] " +"до диапазона [code][ostart, ostop][/code]. Смотрите также [method lerp] и " +"[method inverse_lerp]. ЕÑли [code]значение[/code] за пределами [code]" +"[istart, istop][/code], тогда, выходное значение тоже будет за пределами " +"[code][ostart, ostop][/code]. ИÑпользуйте [method clamp] Ñо значением " +"полученным от [method range_lerp] еÑли не хотите выходить за пределы.[/" +"code]\n" +"[codeblock]\n" +"range_lerp(75, 0, 100, -1, 1) # Возвращает 0.5\n" +"[/codeblock]\n" +"Ð”Ð»Ñ Ñлучаев где вам нужно неÑколько диапазонов, иÑпользуйте [Curve] или " +"[Gradient]." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1755,10 +1785,10 @@ msgstr "" "в большую Ñторону.\n" "[codeblock]\n" "a = round(2.49) # Возвращает 2.0\n" -"a = round(2.5) # Возвращает 3.0\n" +"a = round(2.5)\t# Возвращает 3.0\n" "a = round(2.51) # Возвращает 3.0\n" "[/codeblock]\n" -"См. также[метод floor], [метод ceil], [метод stepify], и [int]." +"См. также[method floor], [method ceil], [method stepify], и [int]." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1852,14 +1882,15 @@ msgstr "" "S-образной кривой, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑоответÑтвует значению [code]s[/code] между " "[code]0[/code] и [code]1[/code].\n" "S-Ð¾Ð±Ñ€Ð°Ð·Ð½Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ ÑвлÑетÑÑ ÐºÑƒÐ±Ð¸Ñ‡ÐµÑким Ñрмитовым Ñплайном, заданным функцией " -"[code]f(s) = 3*s^2 - 2*s^3[/code].\n" +"[code]f(y) = 3*y^2 - 2*y^3[/code], где [code]y = (x-from) / (to-from)[/" +"code].\n" "[codeblock]\n" "smoothstep(0, 2, -5.0) # Возвращает 0.0\n" "smoothstep(0, 2, 0.5) # Возвращает 0.15625\n" "smoothstep(0, 2, 1.0) # Возвращает 0.5\n" "smoothstep(0, 2, 2.0) # Возвращает 1.0\n" "[/codeblock]\n" -"Ð’ Ñравнении Ñ [method ease] Ñо значение кривой [code]-1.6521[/code], [метод " +"Ð’ Ñравнении Ñ [method ease] Ñо значение кривой [code]-1.6521[/code], [method " "smoothstep] возвращает наиболее плавную кривую без внезапных изменений " "производной. ЕÑли вам нужно выполнить более продвинутые перемещениÑ, " "иÑпользуйте [Tween] или [AnimationPlayer].\n" @@ -1956,8 +1987,8 @@ msgid "" "print(b[\"a\"]) # Prints 1\n" "[/codeblock]" msgstr "" -"Преобразует форматированную Ñтроку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±Ñ‹Ð»Ð° возвращена [методом " -"var2str] в иÑходное значение.\n" +"Преобразует форматированную Ñтроку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±Ñ‹Ð»Ð° возвращена [method var2str] " +"в иÑходное значение.\n" "[codeblock]\n" "a = '{ \"a\": 1, \"b\": 2 }'\n" "b = str2var(a)\n" @@ -2265,7 +2296,7 @@ msgid "" msgstr "" "ОÑтанавливает выполнение функции и возвращает текущее приоÑтановленное " "ÑоÑтоÑние вызывающей функции.\n" -"Ð’Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вызвать [метод GDScriptFunctionState.resume] на " +"Ð’Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вызвать [method GDScriptFunctionState.resume] на " "ÑоÑтоÑнии Ð´Ð»Ñ Ð²Ð¾Ð·Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ. Ðто аннулирует ÑоÑтоÑние. Внутри " "возобновленной функции [code]yield()[/code] возвращает вÑе, что было " "передано в вызов функции [code]resume()[/code].\n" @@ -2278,21 +2309,21 @@ msgstr "" "работы функции:\n" "[codeblock].\n" "func _ready():\n" -" yield(countdown(), \"completed\") # ожидание Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ " +"\tyield(countdown(), \"completed\") # ожидание Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ " "countdown()\n" -" print('Ready')\n" +"\tprint('Ready')\n" "\n" "func countdown():\n" -" yield(get_tree(), \"idle_frame\") # возвращает объект " +"\tyield(get_tree(), \"idle_frame\") # возвращает объект " "GDScriptFunctionState Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ _ready()\n" -" print(3)\n" -" yield(get_tree().create_timer(1.0), \"timeout\")\n" -" print(2)\n" -" yield(get_tree().create_timer(1.0), \"timeout\")\n" -" print(1)\n" -" yield(get_tree().create_timer(1.0), \"timeout\")\n" +"\tprint(3)\n" +"\tyield(get_tree().create_timer(1.0), \"timeout\")\n" +"\tprint(2)\n" +"\tyield(get_tree().create_timer(1.0), \"timeout\")\n" +"\tprint(1)\n" +"\tyield(get_tree().create_timer(1.0), \"timeout\")\n" "\n" -"# печатает:\n" +"# выведет:\n" "# 3\n" "# 2\n" "# 1\n" @@ -13808,6 +13839,7 @@ msgid "Camera node for 2D scenes." msgstr "" #: doc/classes/Camera2D.xml +#, fuzzy msgid "" "Camera node for 2D scenes. It forces the screen (current layer) to scroll " "following this node. This makes it easier (and faster) to program scrollable " @@ -13836,7 +13868,7 @@ msgstr "" "Обратите внимание, что положение узла [Camera2D] [code][/code] не отражает " "фактичеÑкое положение Ñкрана, которое может отличатьÑÑ Ð¸Ð·-за примененного " "ÑÐ³Ð»Ð°Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸Ð»Ð¸ ограничений. Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñ€ÐµÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ " -"иÑпользовать [метод get_camera_screen_center]." +"иÑпользовать [method get_camera_screen_center]." #: doc/classes/Camera2D.xml doc/classes/TileMap.xml doc/classes/TileSet.xml msgid "2D Isometric Demo" @@ -16052,11 +16084,11 @@ msgstr "" "ÑвойÑтва (например, CanvasItem.modulate) могут принимать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐµ 1 " "(переÑвет или цвета HDR).\n" "Ð’Ñ‹ также можете Ñоздать цвет из Ñтандартизированных имен цветов Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ " -"[метода @GDScript.ColorN] или непоÑредÑтвенно иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ðµ здеÑÑŒ " +"[method @GDScript.ColorN] или непоÑредÑтвенно иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ðµ здеÑÑŒ " "цветовые конÑтанты. Стандартизированный набор цветов оÑнован на [url=https://" "en.wikipedia.org/wiki/X11_color_names]именах цветов X11[/url].\n" "ЕÑли вы хотите задать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² диапазоне от 0 до 255, вам Ñледует " -"иÑпользовать [метод @GDScript.Color8].\n" +"иÑпользовать [method @GDScript.Color8].\n" "[b]Примечание:[/b] Ð’ булевом контекÑте значение Color будет равно " "[code]false[/code], еÑли оно равно [code]Color(0, 0, 0, 0, 1)[/code] " "(непрозрачный черный). Ð’ противном Ñлучае значение Color вÑегда будет равно " @@ -17703,24 +17735,24 @@ msgid "" msgstr "" "Виртуальный метод, который должен быть реализован пользователем. ИÑпользуйте " "Ñтот метод Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ и приема входных данных на Ñлементах " -"пользовательÑкого интерфейÑа. См. [метод accept_event].\n" +"пользовательÑкого интерфейÑа. См. [method accept_event].\n" "Пример: щелчок по Ñлементу управлениÑ.\n" "[codeblock].\n" "func _gui_input(event):\n" -" if event is InputEventMouseButton:\n" -" if event.button_index == BUTTON_LEFT and event.pressed:\n" -" print(\"Ðа Ð¼ÐµÐ½Ñ Ð½Ð°Ð¶Ð°Ð»Ð¸ D:\")\n" +"\tif event is InputEventMouseButton:\n" +"\t\tif event.button_index == BUTTON_LEFT and event.pressed:\n" +"\t\t\tprint(\"Ðа Ð¼ÐµÐ½Ñ Ð½Ð°Ð¶Ð°Ð»Ð¸ D:\")\n" "[/codeblock].\n" "Событие не Ñработает, еÑли:\n" -"* щелчок вне Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (Ñм. [метод has_point]);\n" +"* щелчок вне Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (Ñм. [method has_point]);\n" "* у Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ [member mouse_filter] уÑтановлено значение [constant " "MOUSE_FILTER_IGNORE];\n" "* Ñлемент ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð³Ð¾Ñ€Ð¾Ð¶ÐµÐ½ другим [Control] Ñверху, у которого [member " "mouse_filter] не уÑтановлен на [constant MOUSE_FILTER_IGNORE];\n" "* родитель Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð¼ÐµÐµÑ‚ [member mouse_filter], уÑтановленный на " "[constant MOUSE_FILTER_STOP] или принÑл Ñобытие;\n" -"* Ñобытие проиÑходит вне прÑмоугольника родителÑ, и у Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½ [член " -"rect_clip_content] или [метод _clips_input].\n" +"* Ñобытие проиÑходит вне прÑмоугольника родителÑ, и у Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½ " +"[member rect_clip_content] или [method _clips_input].\n" "[b]Примечание:[/b] Положение ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¾Ñ‚Ð½Ð¾Ñительно начала Ñлемента управлениÑ." #: doc/classes/Control.xml @@ -17852,7 +17884,7 @@ msgstr "" "получении Ñлементов темы Ð´Ð»Ñ Ñлемента управлениÑ.\n" "[b]Примечание:[/b] Переопределение можно удалить, приÑвоив ему значение " "[code]null[/code]. Ðто поведение уÑтарело и будет удалено в верÑии 4.0, " -"иÑпользуйте [метод remove_stylebox_override] вмеÑто Ñтого.\n" +"иÑпользуйте [method remove_stylebox_override] вмеÑто Ñтого.\n" "См. также [метод get_stylebox].\n" "[b]Пример Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑвойÑтва в StyleBox путем его дублированиÑ:[/b]\n" "[codeblock]\n" @@ -17867,7 +17899,7 @@ msgstr "" "$MyButton.add_stylebox_override(\"normal\", new_stylebox_normal)\n" "# Удалите переопределение Ñтилей.\n" "$MyButton.add_stylebox_override(\"normal\", null)\n" -"[/codeblock]." +"[/codeblock]" #: doc/classes/Control.xml msgid "" @@ -18583,7 +18615,7 @@ msgstr "" "необходимое Ð´Ð»Ñ Ð¿Ð¾ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð²Ñплывающей подÑказки Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ опции [code]gui/" "timers/tooltip_delay_sec[/code] в ÐаÑтройках проекта.\n" "Ð’ÑÐ¿Ð»Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð´Ñказка будет иÑпользовать либо реализацию по умолчанию, либо " -"пользовательÑкую, которую вы можете Ñоздать, переопределив [метод " +"пользовательÑкую, которую вы можете Ñоздать, переопределив [method " "_make_custom_tooltip]. Ð’ÑÐ¿Ð»Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð´Ñказка по умолчанию включает " "[PopupPanel] и [Label], ÑвойÑтва темы которых можно наÑтроить Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ " "методов [Theme] Ñ [code]\"TooltipPanel\"[/code] и [code]\"TooltipLabel\"[/" @@ -23673,17 +23705,17 @@ msgstr "" "ÑоÑтоÑние можно было воÑÑтановить при возврате на вкладку). Ðти данные " "автоматичеÑки ÑохранÑÑŽÑ‚ÑÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñцены в файле [code]editstate[/code] в " "папке метаданных редактора. ЕÑли вы хотите Ñохранить глобальные (незавиÑимые " -"от Ñцены) данные редактора Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ плагина, вы можете иÑпользовать [метод " -"get_window_layout] вмеÑто Ñтого.\n" +"от Ñцены) данные редактора Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ плагина, вы можете иÑпользовать " +"[method get_window_layout] вмеÑто Ñтого.\n" "ИÑпользуйте [method set_state] Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñохраненного ÑоÑтоÑниÑ.\n" "[b]Примечание:[/b] Ðтот метод не Ñледует иÑпользовать Ð´Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð²Ð°Ð¶Ð½Ñ‹Ñ… " "наÑтроек, которые должны ÑохранÑÑ‚ÑŒÑÑ Ð² проекте.\n" "[b]Примечание:[/b] Ð”Ð»Ñ ÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð¾Ð³Ð¾ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸ воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑоÑтоÑÐ½Ð¸Ñ " -"необходимо реализовать [метод get_plugin_name].\n" +"необходимо реализовать [method get_plugin_name].\n" "[codeblock].\n" "func get_state():\n" -" var state = {\"zoom\": zoom, \"preferred_color\": my_color}\n" -" return state\n" +"\tvar state = {\"zoom\": zoom, \"preferred_color\": my_color}\n" +"\treturn state\n" "[/codeblock]" #: doc/classes/EditorPlugin.xml @@ -27854,7 +27886,7 @@ msgstr "" "Вершины каждого многоугольника будут округлены в ÑоответÑтвии Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼ " "[code]join_type[/code], Ñм. [enum PolyJoinType].\n" "Ð’ результате операции может быть получен внешний многоугольник (граница) и " -"внутренний многоугольник (отверÑтие), которые можно отличить, вызвав [метод " +"внутренний многоугольник (отверÑтие), которые можно отличить, вызвав [method " "is_polygon_clockwise].\n" "[b]Примечание:[/b] Ð”Ð»Ñ Ñпециального перевода вершин многоугольника " "иÑпользуйте метод [method Transform2D.xform]:\n" @@ -28261,9 +28293,9 @@ msgstr "" "занимает от 5 до 20 Ñекунд в большинÑтве Ñцен. Уменьшение [member subdiv] " "может уÑкорить запекание.\n" "[b]Примечание:[/b] [GeometryInstance]Ñ‹ и [Light]Ñ‹ должны быть полноÑтью " -"готовы до вызова [метода bake]. ЕÑли вы Ñоздаете их процедурно и некоторые " +"готовы до вызова [method bake]. ЕÑли вы Ñоздаете их процедурно и некоторые " "Ñетки или оÑвещение отÑутÑтвуют в вашем запекаемом [GIProbe], иÑпользуйте " -"[code]call_deferred(\"bake\")[/code] вмеÑто прÑмого вызова [метода bake]." +"[code]call_deferred(\"bake\")[/code] вмеÑто прÑмого вызова [method bake]." #: doc/classes/GIProbe.xml msgid "Calls [method bake] with [code]create_visual_debug[/code] enabled." @@ -30899,14 +30931,14 @@ msgid "" "in the URL. See [method String.http_escape] for an example." msgstr "" "Создает Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° базовом [HTTPClient]. ЕÑли нет ошибок конфигурации, " -"пытаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ [метод HTTPClient.connect_to_host] и " -"передает параметры в [метод HTTPClient.request].\n" +"пытаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ [method HTTPClient.connect_to_host] и " +"передает параметры в [method HTTPClient.request].\n" "Возвращает [constant OK], еÑли Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑƒÑпешно Ñоздан. (Ðто не означает, что " -"Ñервер ответил), [конÑтанта ERR_UNCONFIGURED], еÑли не находитÑÑ Ð² дереве, " -"[конÑтанта ERR_BUSY], еÑли вÑе еще обрабатывает предыдущий запроÑ, " -"[конÑтанта ERR_INVALID_PARAMETER], еÑли Ð·Ð°Ð´Ð°Ð½Ð½Ð°Ñ Ñтрока не ÑвлÑетÑÑ " -"правильным форматом URL, или [конÑтанта ERR_CANT_CONNECT], еÑли не " -"иÑпользуетÑÑ Ð¿Ð¾Ñ‚Ð¾Ðº и [HTTPClient] не может ÑоединитьÑÑ Ñ Ñ…Ð¾Ñтом.\n" +"Ñервер ответил), [constant ERR_UNCONFIGURED], еÑли не находитÑÑ Ð² дереве, " +"[constant ERR_BUSY], еÑли вÑе еще обрабатывает предыдущий запроÑ, [constant " +"ERR_INVALID_PARAMETER], еÑли Ð·Ð°Ð´Ð°Ð½Ð½Ð°Ñ Ñтрока не ÑвлÑетÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ñ‹Ð¼ форматом " +"URL, или [constant ERR_CANT_CONNECT], еÑли не иÑпользуетÑÑ Ð¿Ð¾Ñ‚Ð¾Ðº и " +"[HTTPClient] не может ÑоединитьÑÑ Ñ Ñ…Ð¾Ñтом.\n" "[b]Примечание:[/b] ЕÑли [code]метод[/code] ÑвлÑетÑÑ [constant HTTPClient." "METHOD_GET], Ð¿Ð¾Ð»ÐµÐ·Ð½Ð°Ñ Ð½Ð°Ð³Ñ€ÑƒÐ·ÐºÐ°, Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ñ‡ÐµÑ€ÐµÐ· [code]request_data[/" "code], может быть проигнорирована Ñервером или даже привеÑти к отклонению " @@ -32299,7 +32331,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml @@ -34067,38 +34103,38 @@ msgid "" "[b]Note:[/b] Only available in the HTML5 platform." msgstr "" "JavaScriptObject иÑпользуетÑÑ Ð´Ð»Ñ Ð²Ð·Ð°Ð¸Ð¼Ð¾Ð´ÐµÐ¹ÑÑ‚Ð²Ð¸Ñ Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð°Ð¼Ð¸ JavaScript, " -"полученными или Ñозданными Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [метода JavaScript.get_interface], " -"[метода JavaScript.create_object] или [метода JavaScript.create_callback].\n" +"полученными или Ñозданными Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [method JavaScript.get_interface], " +"[method JavaScript.create_object] или [method JavaScript.create_callback].\n" "Пример:\n" "[codeblock]\n" -"раÑширÑет Node\n" +"extends Node\n" "\n" "var _my_js_callback = JavaScript.create_callback(self, \"myCallback\") # Ðта " "ÑÑылка должна быть Ñохранена\n" "var console = JavaScript.get_interface(\"console\")\n" "\n" "func _init():\n" -" var buf = JavaScript.create_object(\"ArrayBuffer\", 10) # новый " +"\tvar buf = JavaScript.create_object(\"ArrayBuffer\", 10) # новый " "ArrayBuffer(10)\n" -" print(buf) # печатает [JavaScriptObject:OBJECT_ID]\n" -" var uint8arr = JavaScript.create_object(\"Uint8Array\", buf) # новый " +"\tprint(buf) # печатает [JavaScriptObject:OBJECT_ID]\n" +"\tvar uint8arr = JavaScript.create_object(\"Uint8Array\", buf) # новый " "Uint8Array(buf)\n" -" uint8arr[1] = 255\n" -" prints(uint8arr[1], uint8arr.byteLength) # печатает 255 10\n" -" console.log(uint8arr) # печатает в конÑоли браузера \"Uint8Array(10) " -"[ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\"\n" +"\tuint8arr[1] = 255\n" +"\tprints(uint8arr[1], uint8arr.byteLength) # печатает 255 10\n" +"\tconsole.log(uint8arr) # печатает в конÑоли браузера \"Uint8Array(10) [ 0, " +"255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\"\n" "\n" -" # Ðквивалент JavaScript: Array.from(uint8arr).forEach(myCallback)\n" -" JavaScript.get_interface(\"Array\").from(uint8arr)." +"\t# Ðквивалент JavaScript: Array.from(uint8arr).forEach(myCallback)\n" +"\tJavaScript.get_interface(\"Array\").from(uint8arr)." "forEach(_my_js_callback)\n" "\n" "func myCallback(args):\n" -" # Будет вызван Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸, переданными в обратный вызов \"forEach\".\n" -" # [0, 0, [JavaScriptObject:1173]]\n" -" # [255, 1, [JavaScriptObject:1173]]\n" -" # ...\n" -" # [0, 9, [JavaScriptObject:1180]]\n" -" print(args)\n" +"\t# Будет вызван Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸, переданными в обратный вызов \"forEach\".\n" +"\t# [0, 0, [JavaScriptObject:1173]]\n" +"\t# [255, 1, [JavaScriptObject:1173]]\n" +"\t# ...\n" +"\t# [0, 9, [JavaScriptObject:1180]]\n" +"\tprint(args)\n" "[/codeblock].\n" "[b]Примечание:[/b] ДоÑтупно только в платформе HTML5." @@ -39775,7 +39811,7 @@ msgstr "Возвращает значение задержки данного к msgid "" "Returns the normal for the point returned by [method map_get_closest_point]." msgstr "" -"Возвращает нормаль Ð´Ð»Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸, возвращенной [методом map_get_closest_point]." +"Возвращает нормаль Ð´Ð»Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸, возвращенной [method map_get_closest_point]." #: doc/classes/NavigationServer.xml msgid "" @@ -39976,10 +40012,10 @@ msgstr "" "пирами, чтобы гарантировать, что пропуÑÐºÐ½Ð°Ñ ÑпоÑобноÑÑ‚ÑŒ пиров не будет " "превышена. Параметры пропуÑкной ÑпоÑобноÑти также определÑÑŽÑ‚ размер окна " "ÑоединениÑ, которое ограничивает количеÑтво надежных пакетов, которые могут " -"находитьÑÑ Ð² пути в любой момент времени. Возвращает [конÑтанту OK], еÑли " -"клиент был Ñоздан, [конÑтанту ERR_ALREADY_IN_USE], еÑли данный ÑкземплÑÑ€ " +"находитьÑÑ Ð² пути в любой момент времени. Возвращает [constant OK], еÑли " +"клиент был Ñоздан, [constant ERR_ALREADY_IN_USE], еÑли данный ÑкземплÑÑ€ " "NetworkedMultiplayerENet уже имеет открытое Ñоединение (в Ñтом Ñлучае " -"необходимо Ñначала вызвать [метод close_connection]) или [конÑтанту " +"необходимо Ñначала вызвать [method close_connection]) или [constant " "ERR_CANT_CREATE], еÑли клиент не может быть Ñоздан. ЕÑли указано " "[code]client_port[/code], клиент также будет Ñлушать указанный порт; Ñто " "полезно Ð´Ð»Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… методов обхода NAT." @@ -75012,23 +75048,24 @@ msgid "" "viewport_set_render_direct_to_screen]." msgstr "" "Копирует видовой Ñкран в облаÑÑ‚ÑŒ Ñкрана, указанную [code]rect[/code]. ЕÑли " -"[член Viewport.render_direct_to_screen] равен [code]true[/code], то вьюпорт " -"не иÑпользует фреймбуфер и Ñодержимое вьюпорта выводитÑÑ Ð½ÐµÐ¿Ð¾ÑредÑтвенно на " -"Ñкран. Однако обратите внимание, что корневой видовой Ñкран риÑуетÑÑ " -"поÑледним, поÑтому он будет риÑоватьÑÑ Ð¿Ð¾Ð²ÐµÑ€Ñ… Ñкрана. СоответÑтвенно, вы " -"должны уÑтановить корневой видовой Ñкран на облаÑÑ‚ÑŒ, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð½Ðµ покрывает " -"облаÑÑ‚ÑŒ, к которой вы прикрепили Ñтот видовой Ñкран.\n" +"[member Viewport.render_direct_to_screen] равен [code]true[/code], то " +"вьюпорт не иÑпользует фреймбуфер и Ñодержимое вьюпорта выводитÑÑ " +"непоÑредÑтвенно на Ñкран. Однако обратите внимание, что корневой видовой " +"Ñкран риÑуетÑÑ Ð¿Ð¾Ñледним, поÑтому он будет риÑоватьÑÑ Ð¿Ð¾Ð²ÐµÑ€Ñ… Ñкрана. " +"СоответÑтвенно, вы должны уÑтановить корневой видовой Ñкран на облаÑÑ‚ÑŒ, " +"ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð½Ðµ покрывает облаÑÑ‚ÑŒ, к которой вы прикрепили Ñтот видовой Ñкран.\n" "Ðапример, вы можете уÑтановить корневой видовой Ñкран так, чтобы он вообще " "не отриÑовывалÑÑ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ñледующий код:\n" "[codeblock].\n" "func _ready():\n" -" get_viewport().set_attach_to_screen_rect(Rect2())\n" -" $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n" +"\tget_viewport().set_attach_to_screen_rect(Rect2())\n" +"\t$Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n" "[/codeblock].\n" "ИÑпользование Ñтого метода может привеÑти к значительной оптимизации, " "оÑобенно на уÑтройÑтвах низкого клаÑÑа. Однако за Ñто приходитÑÑ " "раÑплачиватьÑÑ Ð½ÐµÐ¾Ð±Ñ…Ð¾Ð´Ð¸Ð¼Ð¾Ñтью управлÑÑ‚ÑŒ видовыми Ñкранами вручную. Ð”Ð»Ñ " -"дальнейшей оптимизации Ñмотрите [метод viewport_set_render_direct_to_screen]." +"дальнейшей оптимизации Ñмотрите [method " +"viewport_set_render_direct_to_screen]." #: doc/classes/VisualServer.xml msgid "" diff --git a/doc/translations/sk.po b/doc/translations/sk.po index 3a58e3f2a9..d82d0b12ee 100644 --- a/doc/translations/sk.po +++ b/doc/translations/sk.po @@ -29911,7 +29911,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/sr_Cyrl.po b/doc/translations/sr_Cyrl.po index 2846de07bb..2fccf2bef4 100644 --- a/doc/translations/sr_Cyrl.po +++ b/doc/translations/sr_Cyrl.po @@ -29922,7 +29922,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/sv.po b/doc/translations/sv.po index 65cad9bf8a..b4ec51f179 100644 --- a/doc/translations/sv.po +++ b/doc/translations/sv.po @@ -29909,7 +29909,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/th.po b/doc/translations/th.po index 54fbdbfe27..0ca308df1c 100644 --- a/doc/translations/th.po +++ b/doc/translations/th.po @@ -30049,7 +30049,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/tl.po b/doc/translations/tl.po index a9b6a9e2a9..a3d46e6b1d 100644 --- a/doc/translations/tl.po +++ b/doc/translations/tl.po @@ -29997,7 +29997,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/tr.po b/doc/translations/tr.po index 5d8f2afe29..a41bb69483 100644 --- a/doc/translations/tr.po +++ b/doc/translations/tr.po @@ -30744,7 +30744,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/uk.po b/doc/translations/uk.po index 3714c11d88..6c071cee85 100644 --- a/doc/translations/uk.po +++ b/doc/translations/uk.po @@ -20,8 +20,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-11-25 12:13+0000\n" -"Last-Translator: Лев ДворÑкий <ne3r0n@gmail.com>\n" +"PO-Revision-Date: 2022-12-28 14:08+0000\n" +"Last-Translator: KazanskiyMaks <kazanskiy.maks@gmail.com>\n" "Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/" "godot-class-reference/uk/>\n" "Language: uk\n" @@ -30,7 +30,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -106,13 +106,11 @@ msgid "Getter" msgstr "Отримувач" #: doc/tools/make_rst.py -#, fuzzy msgid "" "This method should typically be overridden by the user to have any effect." msgstr "Зазвичай, цей метод перевизначаєтьÑÑ ÐºÐ¾Ñ€Ð¸Ñтувачем, щоб він мав вплив." #: doc/tools/make_rst.py -#, fuzzy msgid "" "This method has no side effects. It doesn't modify any of the instance's " "member variables." @@ -120,13 +118,11 @@ msgstr "" "Цей метод не має побічних ефектів. Ðе змінює ніÑку змінну екземплÑра об'єкта." #: doc/tools/make_rst.py -#, fuzzy msgid "" "This method accepts any number of arguments after the ones described here." msgstr "Цей метод приймає будь-Ñке чиÑло аргументів піÑÐ»Ñ Ð¾Ð¿Ð¸Ñаних тут." #: doc/tools/make_rst.py -#, fuzzy msgid "This method is used to construct a type." msgstr "Цей метод викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ типів." @@ -136,8 +132,8 @@ msgid "" "This method doesn't need an instance to be called, so it can be called " "directly using the class name." msgstr "" -"Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтаннÑ, цей метод не потребує ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¾Ð±'єкта, тому він може " -"бути викликаним напрÑму вказавши назву клаÑу." +"Ð”Ð»Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑƒ, метод не потребує ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¾Ð±'єкта, тому він може бути " +"викориÑтаним проÑто вказавши назву клаÑу." #: doc/tools/make_rst.py msgid "" @@ -285,22 +281,22 @@ msgid "" "[/codeblock]" msgstr "" "ПеревірÑÑ”, чи [code]condition[/code] дорівнює [code]true[/code]. Якщо " -"[code]condition[/code] дорівнює [code]false[/code], буде згенеровано " -"помилку. Якщо виконуєтьÑÑ Ñƒ редакторі, проєкт буде також призупинено, поки " -"ви не продовжите його. Може бути викориÑтано, Ñк більш дієва форма [method " -"push_error] Ð´Ð»Ñ Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº розробникам проєкту, або допоміжним " -"кориÑтувачам.\n" +"[code]condition[/code] дорівнює [code]false[/code], буде Ñтворено помилку. " +"Якщо виконуєтьÑÑ Ð² редакторі, проєкт також буде призупинено, поки ви не " +"відновите його роботу. Можна викориÑтати, Ñк більш дієву форму [method " +"push_error] Ð´Ð»Ñ Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº розробникам проєкту, або кориÑтувачам " +"Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ (add-on).\n" "[b]Ðотатка:[/b] З міркувань продуктивноÑÑ‚Ñ–, код вÑередині [method assert] " -"виконуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ у діагноÑтичних збірках, або коли проєкт виконуєтьÑÑ Ñƒ " -"редакторі. Ðе викориÑтовуйте код, Ñкий негативно впливає на Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ " -"[method assert]. Інакше, проєкт буде поводити Ñебе інакше, Ñкщо він буде " -"екÑпортованим у режимі публікації.\n" +"виконуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ у діагноÑтичних збірках, або коли проєкт виконуєтьÑÑ Ð² " +"редакторі. Ðе включайте в код, де викориÑÑ‚Ð°Ð½Ð½Ñ [method assert] призведе до " +"побічних ефектів. У противному разі, проєкт буде поводити Ñебе інакше, Ñкщо " +"він буде екÑпортованим у режимі публікації.\n" "Якщо задано необов'Ñзковий аргумент [code]message[/code], то він буде " "показаний у додаток до Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ \"Assertion failed\". Ви можете " -"ÑкориÑтатиÑÑ Ñ†Ð¸Ð¼ Ð´Ð»Ñ Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… відомоÑтей щодо того, чому перевірку " -"не було пройдено.\n" +"ÑкориÑтатиÑÑ Ñ†Ð¸Ð¼ Ð´Ð»Ñ Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… відомоÑтей щодо причини провалу " +"перевірки.\n" "[codeblock]\n" -"# ПрипуÑтимо, що ви хочете, щоб швидкіÑÑ‚ÑŒ (speed) була у межах від 0 до 20.\n" +"# ПрипуÑтимо, ви хочете, щоб швидкіÑÑ‚ÑŒ (speed) була у межах від 0 до 20.\n" "var speed = -10\n" "assert(speed < 20) # ІÑтина, програма продовжить виконаннÑ\n" "assert(speed >= 0) # Хиба, програму буде зупинено\n" @@ -375,6 +371,7 @@ msgstr "" "полÑрну ÑиÑтему (відÑтань до початку координат та кут)." #: modules/gdscript/doc_classes/@GDScript.xml +#, fuzzy msgid "" "Rounds [code]s[/code] upward (towards positive infinity), returning the " "smallest whole number that is not less than [code]s[/code].\n" @@ -384,6 +381,13 @@ msgid "" "[/codeblock]\n" "See also [method floor], [method round], [method stepify], and [int]." msgstr "" +"Заокруглює [code]s[/code] вгору (до додатної неÑкінченноÑÑ‚Ñ–), повертаючи " +"найменше чиÑло, ще не менше за [code]s[/code].\n" +"[codeblock]\n" +"a = ceil(1.45) # a дорівнює 2.0\n" +"a = ceil(1.001) # a дорівнює 2.0\n" +"[/codeblock]\n" +"Також переглÑньте [method floor], [method round], [method stepify] та [int]." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -396,6 +400,13 @@ msgid "" "[/codeblock]\n" "This is the inverse of [method ord]." msgstr "" +"Повертає Ñимвол, Ñк Ð Ñдок з даного Юнікод коду(що ÑуміÑний з ASCII кодом).\n" +"[codeblock]\n" +"a = char(65) # a дорівнює \"A\"\n" +"a = char(65 + 32) # a дорівнює \"a\"\n" +"a = char(8364) # a дорівнює \"€\"\n" +"[/codeblock]\n" +"Це протилежніÑÑ‚ÑŒ до [method ord]." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -407,6 +418,13 @@ msgid "" "a = clamp(15, 1, 20) # a is 15\n" "[/codeblock]" msgstr "" +"ЗатиÑкує [code]value[/code] та повертає значеннÑ, що не менше за [code]min[/" +"code] Ñ– не більше за [code]max[/code].\n" +"[codeblock]\n" +"a = clamp(1000, 1, 20) # a дорівнює 20\n" +"a = clamp(-10, 1, 20) # a дорівнює 1\n" +"a = clamp(15, 1, 20) # a дорівнює 15\n" +"[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -421,6 +439,16 @@ msgid "" "print(a.length())\n" "[/codeblock]" msgstr "" +"Конвертує один тип в інший у найкращий ÑпоÑіб. Параметр [code]type[/code] " +"викориÑтовує Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· [enum Variant.Type].\n" +"[codeblock]\n" +"a = Vector2(1, 0)\n" +"# Виводить 1\n" +"print(a.length())\n" +"a = convert(a, TYPE_STRING)\n" +"# Виводить 6, бо Ñ€Ñдок \"(1, 0)\" ÑкладаєтьÑÑ Ð· 6 Ñимволів\n" +"print(a.length())\n" +"[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml #, fuzzy @@ -431,11 +459,10 @@ msgid "" "a = cos(PI) # a is -1.0\n" "[/codeblock]" msgstr "" -"Повертає абÑолютне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñƒ [code]s[/code] (тобто Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±ÐµÐ· " -"знака, працює Ð´Ð»Ñ Ñ†Ñ–Ð»Ð¸Ñ… чиÑел Ñ– чиÑел із рухомою крапкою).\n" +"Повертає коÑÐ¸Ð½ÑƒÑ ÐºÑƒÑ‚Ð° [code]s[/code] в радіанах.\n" "[codeblock]\n" -"# a дорівнює 1\n" -"a = abs(-1)\n" +"a = cos(TAU) # a дорівнює 1.0\n" +"a = cos(PI) # a дорівнює -1.0\n" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml @@ -452,11 +479,11 @@ msgstr "" #: modules/gdscript/doc_classes/@GDScript.xml msgid "Converts from decibels to linear energy (audio)." -msgstr "" +msgstr "Перетворює з децибел в лінійну енергію (аудіо)." #: modules/gdscript/doc_classes/@GDScript.xml msgid "Deprecated alias for [method step_decimals]." -msgstr "" +msgstr "ЗаÑтарілий пÑевдонім Ð´Ð»Ñ [method step_decimals]." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -468,6 +495,13 @@ msgid "" "a = dectime(60, 10, 0.1)) # a is 59.0\n" "[/codeblock]" msgstr "" +"[b]Ðотатка:[/b] [code]dectime[/code] заÑтарілий Ñ– буде вилучений в Godot " +"4.0, натоміÑÑ‚ÑŒ краще викориÑтовуйте [method move_toward].\n" +"Повертає результат [code]value[/code] зменшений на [code]step[/code] * " +"[code]amount[/code].\n" +"[codeblock]\n" +"a = dectime(60, 10, 0.1)) # a дорівнює 59.0\n" +"[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -489,6 +523,23 @@ msgid "" "want a true content-aware comparison, you have to use [code]deep_equal[/" "code]." msgstr "" +"Порівнює два значеннÑ, шлÑхом порівнÑÐ½Ð½Ñ Ñ—Ñ… реального вміÑту, рекурÑивно Ð´Ð»Ñ " +"будь-Ñкого [Array] чи [Dictionary] аж до найглибшого рівнÑ.\n" +"Порівнюючи з [code]==[/code], відмітимо:\n" +"- Ð”Ð»Ñ [code]null[/code], [code]int[/code], [code]float[/code], [code]String[/" +"code], [code]Object[/code] та [code]RID[/code] що [code]deep_equal[/code], " +"що [code]==[/code] працюють однаково.\n" +"- Ð”Ð»Ñ [code]Dictionary[/code], [code]==[/code] виÑвлÑÑ” рівніÑÑ‚ÑŒ тоді й " +"тільки тоді, коли йде порівнÑÐ½Ð½Ñ Ð· цим Ñамим [code]Dictionary[/code], без " +"рекурÑÑ–Ñ— чи будь-Ñкого Ð²Ñ€Ð°Ñ…ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¼Ñ–Ñту.\n" +"- Ð”Ð»Ñ [code]Array[/code], [code]==[/code] виÑвлÑÑ” рівніÑÑ‚ÑŒ тоді й тільки " +"тоді, коли кожний елемент у першому [code]Array[/code] дорівнює відповідному " +"елементу в другому [code]Array[/code], де порівнÑÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¸Ñ‚ÑŒ через " +"[code]==[/code]. Це означає, що [code]==[/code] рекурÑивно порівнює " +"[code]Array[/code], але не [code]Dictionary[/code].\n" +"Загалом, Ñкщо у Ð²Ð°Ñ Ð¿Ð¾Ñ‚ÐµÐ½Ñ†Ñ–Ð¹Ð½Ð¾ викориÑтовуєтьÑÑ [code]Dictionary[/code], Ñ– " +"вам потрібно порівнÑÐ½Ð½Ñ Ð· урахуваннÑм вміÑту, викориÑтовуйте " +"[code]deep_equal[/code]." #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -30098,7 +30149,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/vi.po b/doc/translations/vi.po index 962440bfab..36ef54b096 100644 --- a/doc/translations/vi.po +++ b/doc/translations/vi.po @@ -30410,7 +30410,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml diff --git a/doc/translations/zh_CN.po b/doc/translations/zh_CN.po index 966ec9b0f9..773dda130e 100644 --- a/doc/translations/zh_CN.po +++ b/doc/translations/zh_CN.po @@ -3,7 +3,7 @@ # Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). # This file is distributed under the same license as the Godot source code. # -# Haoyu Qiu <timothyqiu32@gmail.com>, 2020, 2021, 2022. +# Haoyu Qiu <timothyqiu32@gmail.com>, 2020, 2021, 2022, 2023. # fangxvan <2661712415@qq.com>, 2020. # yzt <834950797@qq.com>, 2020. # 懵逼Kitty <m1330586660@163.com>, 2020, 2021. @@ -37,7 +37,7 @@ # Juer Genie Whang <2695996944@qq.com>, 2021. # SimonChang <simon_chang@foxmail.com>, 2021. # zeng haochen <m18621006730@163.com>, 2021. -# suplife <2634557184@qq.com>, 2021. +# suplife <2634557184@qq.com>, 2021, 2023. # Magian <magian1127@gmail.com>, 2021, 2022. # ji233 <27987772@qq.com>, 2021. # 沈士超 <shenshichao920@hotmail.com>, 2021. @@ -64,7 +64,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-12-12 06:48+0000\n" +"PO-Revision-Date: 2023-01-09 20:42+0000\n" "Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n" "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "godot-engine/godot-class-reference/zh_Hans/>\n" @@ -73,7 +73,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -730,7 +730,6 @@ msgstr "" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns an array of dictionaries representing the current call stack. See " "also [method print_stack].\n" @@ -754,7 +753,7 @@ msgid "" "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." msgstr "" -"返回一个表示当å‰è°ƒç”¨å †æ ˆçš„å—典数组。\n" +"返回一个表示当å‰è°ƒç”¨å †æ ˆçš„å—典数组。å¦è¯·å‚阅 [method print_stack]。\n" "[codeblock]\n" "func _ready():\n" " foo()\n" @@ -769,7 +768,11 @@ msgstr "" "[codeblock]\n" "[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, " "source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]\n" -"[/codeblock]" +"[/codeblock]\n" +"[b]注æ„:[/b]è¿è¡Œä¸çš„实例连接到调试æœåŠ¡å™¨ï¼ˆä¾‹å¦‚编辑器实例)åŽï¼Œ[method " +"get_stack] æ‰èƒ½æ£å¸¸å·¥ä½œã€‚[method get_stack] æ— æ³•åœ¨ä½¿ç”¨å‘布模å¼å¯¼å‡ºçš„项目ä¸æ£" +"常工作。使用调试模å¼å¯¼å‡ºçš„项目如果没有连接到调试æœåŠ¡å™¨ï¼Œåˆ™è¯¥å‡½æ•°ä¹Ÿæ— 法æ£å¸¸å·¥" +"作。" #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -1367,6 +1370,15 @@ msgid "" "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." msgstr "" +"输出当å‰ä»£ç ä½ç½®çš„æ ˆè¿½è¸ªã€‚å¦è¯·å‚阅 [method get_stack]。\n" +"控制å°ä¸çš„è¾“å‡ºæ˜¯ç±»ä¼¼è¿™æ ·çš„ï¼š\n" +"[codeblock]\n" +"Frame 0 - res://test.gd:16 in function '_process'\n" +"[/codeblock]\n" +"[b]注æ„:[/b]è¿è¡Œä¸çš„实例连接到调试æœåŠ¡å™¨ï¼ˆä¾‹å¦‚编辑器实例)åŽï¼Œ[method " +"print_stack] æ‰èƒ½æ£å¸¸å·¥ä½œã€‚[method print_stack] æ— æ³•åœ¨ä½¿ç”¨å‘布模å¼å¯¼å‡ºçš„项目" +"ä¸æ£å¸¸å·¥ä½œã€‚使用调试模å¼å¯¼å‡ºçš„项目如果没有连接到调试æœåŠ¡å™¨ï¼Œåˆ™è¯¥å‡½æ•°ä¹Ÿæ— 法æ£" +"常工作。" #: modules/gdscript/doc_classes/@GDScript.xml msgid "" @@ -4407,6 +4419,18 @@ msgid "" "[b]Note:[/b] The final colon is required to specify for properly detecting " "built-in types." msgstr "" +"æ示一个属性代表特定的类型。如果属性为 [constant TYPE_STRING],则å¯ä»¥é€šè¿‡åˆ›å»º" +"对è¯æ¡†è®¾ç½®å…¶ç±»åž‹ã€‚å¦‚æžœä½ éœ€è¦åˆ›å»ºä¸€ä¸ª [Array] æ¥æ”¾ç½®ç‰¹å®šç±»åž‹çš„å…ƒç´ ï¼Œåˆ™ " +"[code]hint_string[/code] 必须使用 [code]\":\"[/code] æ¥ç¼–ç 嵌套类型,使用 " +"[code]\"/\"[/code] æ¥æŒ‡å®š [Resource] 类型。例如:\n" +"[codeblock]\n" +"hint_string = \"%s:\" % [TYPE_INT] # 整数数组。\n" +"hint_string = \"%s:%s:\" % [TYPE_ARRAY, TYPE_REAL] # 浮点数二维数组。\n" +"hint_string = \"%s/%s:Resource\" % [TYPE_OBJECT, TYPE_OBJECT] # 资æºæ•°ç»„。\n" +"hint_string = \"%s:%s/%s:Resource\" % [TYPE_ARRAY, TYPE_OBJECT, TYPE_OBJECT] " +"# 资æºäºŒç»´æ•°ç»„。\n" +"[/codeblock]\n" +"[b]注æ„:[/b]最åŽçš„冒å·æ˜¯å¿…须的,å¦åˆ™æ— 法æ£ç¡®æ£€æµ‹å†…置类型。" #: doc/classes/@GlobalScope.xml msgid "The property is serialized and saved in the scene file (default)." @@ -8808,7 +8832,6 @@ msgstr "" "è¾ƒæ…¢ã€‚è¿™æ˜¯å› ä¸ºæ‰€æœ‰æ”¾ç½®åœ¨åˆ é™¤å…ƒç´ ä¹‹åŽçš„å…ƒç´ éƒ½å¿…é¡»é‡æ–°ç´¢å¼•ã€‚" #: doc/classes/Array.xml -#, fuzzy msgid "" "Assigns the given value to all elements in the array. This can typically be " "used together with [method resize] to create an array with a given size and " @@ -8828,7 +8851,9 @@ msgstr "" "var array = []\n" "array.resize(10)\n" "array.fill(0) # å°† 10 ä¸ªå…ƒç´ éƒ½åˆå§‹åŒ–为 0。\n" -"[/codeblock]" +"[/codeblock]\n" +"[b]注æ„:[/b]如果 [code]value[/code] 为引用类型(派生自 [Object]ã€[Array]ã€" +"[Dictionary] ç‰ï¼‰ï¼Œé‚£ä¹ˆä¼šç”¨åŒä¸€ä¸ªå¯¹è±¡çš„引用填充该数组,å³ä¸ä¼šåˆ›å»ºå‰¯æœ¬ã€‚" #: doc/classes/Array.xml doc/classes/PoolByteArray.xml #: doc/classes/PoolColorArray.xml doc/classes/PoolIntArray.xml @@ -9076,7 +9101,6 @@ msgstr "" "索引之间的å˜åŒ–。" #: doc/classes/Array.xml -#, fuzzy msgid "" "Sorts the array.\n" "[b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/" @@ -9092,6 +9116,9 @@ msgid "" "[/codeblock]" msgstr "" "对数组进行排åºã€‚\n" +"[b]注æ„:[/b]排åºæ‰€ä½¿ç”¨çš„算法并ä¸[url=https://zh.wikipedia.org/wiki/" +"%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95#%E7%A9%A9%E5%AE%9A%E6%80%A7]稳定[/url]。" +"也就是说,使用 [method sort] 时相ç‰çš„值之间的顺åºå¯èƒ½ä¼šæ”¹å˜ã€‚\n" "[b]注æ„:[/b]å—符串按å—æ¯é¡ºåºæŽ’åºï¼ˆä¸Žè‡ªç„¶é¡ºåºç›¸å)。当对一个以数å—åºåˆ—结尾的" "å—符串数组进行排åºæ—¶ï¼Œè¿™å¯èƒ½ä¼šå¯¼è‡´æ„外的行为。请看下é¢çš„例å。\n" "[codeblock]\n" @@ -9101,7 +9128,6 @@ msgstr "" "[/codeblock]" #: doc/classes/Array.xml -#, fuzzy msgid "" "Sorts the array using a custom method. The arguments are an object that " "holds the method and the name of such method. The custom method receives two " @@ -9135,8 +9161,11 @@ msgstr "" "å¯¹äºŽä¸¤ä¸ªå…ƒç´ [code]a[/code] å’Œ [code]b[/code],如果给定的方法返回 " "[code]true[/code],数组ä¸çš„å…ƒç´ [code]b[/code] å°†æŽ’åœ¨å…ƒç´ [code]a[/code] 之" "åŽã€‚\n" -"[b]注æ„:[/b]ä½ ä¸èƒ½éšæœºåŒ–è¿”å›žå€¼ï¼Œå› ä¸ºå †æŽ’åºç®—æ³•æœŸæœ›ä¸€ä¸ªç¡®å®šçš„ç»“æžœã€‚è€Œè¿™æ ·åšä¼š" -"导致æ„外的行为。\n" +"[b]注æ„:[/b]排åºæ‰€ä½¿ç”¨çš„算法并ä¸[url=https://zh.wikipedia.org/wiki/" +"%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95#%E7%A9%A9%E5%AE%9A%E6%80%A7]稳定[/url]。" +"也就是说,使用 [method sort] 时相ç‰çš„值之间的顺åºå¯èƒ½ä¼šæ”¹å˜ã€‚\n" +"[b]注æ„:[/b]ä¸èƒ½éšæœºè¿”å›žä¸€ä¸ªå€¼ï¼Œå› ä¸ºå †æŽ’åºç®—法期望确定的结果。éšæœºè¿”回一个值" +"会导致æ„外的行为。\n" "[codeblock]\n" "class MyCustomSorter:\n" " static func sort_ascending(a, b):\n" @@ -9787,7 +9816,7 @@ msgid "" "However, at this point in time only one interface can render to an HMD." msgstr "" "调用这个æ¥åˆå§‹åŒ–这个接å£ã€‚第一个被åˆå§‹åŒ–的接å£ç¡®å®šä¸ºä¸»æŽ¥å£ï¼Œç”¨äºŽæ¸²æŸ“输出。\n" -"在åˆå§‹åŒ–了接å£ä¹‹åŽï¼Œéœ€è¦å¯ç”¨è§†çª—çš„ AR/VR 模å¼ï¼Œå°†å¼€å§‹æ¸²æŸ“。\n" +"在åˆå§‹åŒ–了接å£ä¹‹åŽï¼Œéœ€è¦å¯ç”¨è§†å£çš„ AR/VR 模å¼ï¼Œå°†å¼€å§‹æ¸²æŸ“。\n" "[b]注æ„:[/b]对于任何使用 Godot 主输出的设备,如移动 VRï¼Œä½ å¿…é¡»åœ¨ä¸»è§†å£ä¸Šå¯" "用 AR/VR 模å¼ã€‚\n" "å¦‚æžœä½ ä¸ºä¸€ä¸ªå¤„ç†è‡ªå·±è¾“出的平å°è¿™æ ·åšï¼ˆå¦‚ OpenVR),Godot 就会在å±å¹•ä¸Šåªæ˜¾ç¤ºä¸€" @@ -9844,9 +9873,9 @@ msgid "" "[method get_render_targetsize]). Using a separate viewport node frees up the " "main viewport for other purposes." msgstr "" -"这个接å£è¾“出到一个外部设备。如果使用主视区,å±å¹•ä¸Šçš„输出是一个未ç»ä¿®æ”¹çš„左眼" -"或å³çœ¼çš„缓冲区,如果没有将视窗尺寸更改为 [method get_render_targetsize] 的相" -"åŒé•¿å®½æ¯”,则被拉伸。使用一个å•ç‹¬çš„视窗节点å¯ä»¥é‡Šæ”¾å‡ºä¸»è§†åŒºï¼Œç”¨äºŽå…¶ä»–用途。" +"这个接å£è¾“出到一个外部设备。如果使用主视å£ï¼Œå±å¹•ä¸Šçš„输出是一个未ç»ä¿®æ”¹çš„左眼" +"或å³çœ¼çš„缓冲区,如果没有将视å£å°ºå¯¸æ›´æ”¹ä¸º [method get_render_targetsize] 的相" +"åŒé•¿å®½æ¯”,则被拉伸。使用一个å•ç‹¬çš„视å£èŠ‚点å¯ä»¥é‡Šæ”¾å‡ºä¸»è§†å£ï¼Œç”¨äºŽå…¶ä»–用途。" #: doc/classes/ARVRInterface.xml msgid "" @@ -12402,14 +12431,13 @@ msgid "Clears the audio sample data buffer." msgstr "æ¸…é™¤éŸ³é¢‘æ ·æœ¬æ•°æ®ç¼“冲区。" #: doc/classes/AudioStreamGeneratorPlayback.xml -#, fuzzy msgid "" "Returns the number of frames that can be pushed to the audio sample data " "buffer without overflowing it. If the result is [code]0[/code], the buffer " "is full." msgstr "" -"如果å¯ä»¥å°†å¤§å°ä¸º [code]amount[/code] 的缓冲区推é€åˆ°éŸ³é¢‘é‡‡æ ·æ•°æ®ç¼“冲区而ä¸ä½¿å…¶" -"溢出,则返回 [code]true[/code],å¦åˆ™è¿”回 [code]false[/code]。" +"返回能够推é€åˆ°éŸ³é¢‘é‡‡æ ·æ•°æ®ç¼“冲区而ä¸ä½¿å…¶æº¢å‡ºçš„帧数。如果结果为 [code]0[/" +"code],则缓冲区已满。" #: doc/classes/AudioStreamGeneratorPlayback.xml msgid "" @@ -13042,7 +13070,6 @@ msgstr "" "[code]texture(SCREEN_TEXTURE, ...)[/code] 函数在ç€è‰²å™¨è„šæœ¬ä¸å¯¹å…¶è¿›è¡Œè®¿é—®ã€‚" #: doc/classes/BackBufferCopy.xml -#, fuzzy msgid "" "Node for back-buffering the currently-displayed screen. The region defined " "in the [BackBufferCopy] node is buffered with the content of the screen it " @@ -13055,44 +13082,40 @@ msgid "" "derived nodes as [i]siblings[/i] to the [BackBufferCopy] node instead of " "adding them as children." msgstr "" -"用于对当å‰å±å¹•æ˜¾ç¤ºè¿›è¡ŒåŽå°ç¼“冲的节点。BackBufferCopy 节点ä¸å®šä¹‰çš„区域与其覆盖" -"å±å¹•çš„å†…å®¹ä¸€èµ·ç¼“å†²ï¼Œæˆ–è€…æ ¹æ®æ‹·è´æ¨¡å¼è®¾ç½®çš„整个å±å¹•è¿›è¡Œç¼“冲。在ç€è‰²å™¨è„šæœ¬ä¸ä½¿" -"用 [code]texture(SCREEN_TEXTURE, ...)[/code] 函数æ¥è®¿é—®ç¼“冲区。\n" +"用于对当å‰æ˜¾ç¤ºçš„å±å¹•è¿›è¡ŒåŽå°ç¼“冲的节点。[BackBufferCopy] 节点ä¸å®šä¹‰çš„区域与其" +"覆盖å±å¹•çš„å†…å®¹ä¸€èµ·ç¼“å†²ï¼Œæˆ–è€…æ ¹æ®æ‹·è´æ¨¡å¼è®¾ç½®çš„整个å±å¹•è¿›è¡Œç¼“冲。在ç€è‰²å™¨è„šæœ¬" +"ä¸ä½¿ç”¨ [code]texture(SCREEN_TEXTURE, ...)[/code] 函数æ¥è®¿é—®ç¼“冲区。\n" "[b]注æ„:[/b]由于该节点继承自 [Node2D] è€Œéž [Control],锚点和边è·å°†ä¸ä¼šåº”用于" "从 [Control] 派生的å节点。这在调整窗å£å¤§å°æ—¶å¯èƒ½ä¼šå‡ºçŽ°é—®é¢˜ã€‚为é¿å…è¿™ç§æƒ…况," -"请将 [Control] æ´¾ç”ŸèŠ‚ç‚¹æ·»åŠ ä¸º BackBufferCopy 节点的[i]åŒçº§[/i],ä¸è¦å°†å®ƒä»¬æ·»" -"åŠ ä¸ºå…¶å节点。" +"请将 [Control] æ´¾ç”ŸèŠ‚ç‚¹æ·»åŠ ä¸º [BackBufferCopy] 节点的[i]åŒçº§[/i],ä¸è¦å°†å®ƒä»¬" +"æ·»åŠ ä¸ºå…¶å节点。" #: doc/classes/BackBufferCopy.xml msgid "Buffer mode. See [enum CopyMode] constants." msgstr "缓冲区模å¼ã€‚è§ [enum CopyMode] 常é‡ã€‚" #: doc/classes/BackBufferCopy.xml -#, fuzzy msgid "" "The area covered by the [BackBufferCopy]. Only used if [member copy_mode] is " "[constant COPY_MODE_RECT]." msgstr "" -"BackBufferCopy 覆盖的区域。åªæœ‰å½“ [member copy_mode] 是 [constant " +"该 [BackBufferCopy] 所覆盖的区域。åªæœ‰å½“ [member copy_mode] 为 [constant " "COPY_MODE_RECT] æ—¶æ‰ä½¿ç”¨ã€‚" #: doc/classes/BackBufferCopy.xml -#, fuzzy msgid "" "Disables the buffering mode. This means the [BackBufferCopy] node will " "directly use the portion of screen it covers." msgstr "" -"ç¦ç”¨ç¼“冲模å¼ã€‚è¿™æ„å‘³ç€ BackBufferCopy 节点将直接使用它所覆盖的å±å¹•éƒ¨åˆ†ã€‚" +"ç¦ç”¨ç¼“冲模å¼ã€‚è¿™æ„味ç€è¯¥ [BackBufferCopy] 节点将直接使用它所覆盖的å±å¹•éƒ¨åˆ†ã€‚" #: doc/classes/BackBufferCopy.xml -#, fuzzy msgid "[BackBufferCopy] buffers a rectangular region." -msgstr "BackBufferCopy 缓冲一个矩形区域。" +msgstr "[BackBufferCopy] 缓冲一个矩形区域。" #: doc/classes/BackBufferCopy.xml -#, fuzzy msgid "[BackBufferCopy] buffers the entire screen." -msgstr "BackBufferCopy 缓冲整个å±å¹•ã€‚" +msgstr "[BackBufferCopy] 缓冲整个å±å¹•ã€‚" #: doc/classes/BakedLightmap.xml msgid "Prerendered indirect light map for a scene." @@ -14561,9 +14584,9 @@ msgid "" "[Viewport] (or higher viewports) can't be displayed." msgstr "" "相机是一个特殊节点,用于显示从其当å‰ä½ç½®å¯è§çš„内容。相机在最近的 [Viewport] " -"节点ä¸æ³¨å†Œè‡ªå·±ï¼ˆå½“æ ‘ä¸Šè¡Œï¼‰ã€‚æ¯ä¸ªè§†åŒºåªèƒ½æ¿€æ´»ä¸€ä¸ªç›¸æœºã€‚å¦‚æžœåœ¨æ ‘ä¸Šæ²¡æœ‰å¯ç”¨çš„视" -"区,相机将在全局视区ä¸æ³¨å†Œã€‚æ¢å¥è¯è¯´ï¼Œç›¸æœºåªæ˜¯ä¸º [Viewport] æä¾› 3D 显示能" -"åŠ›ï¼Œå¦‚æžœæ²¡æœ‰ï¼Œåˆ™æ— æ³•æ˜¾ç¤ºåœ¨è¯¥ [Viewport] 或更高视区ä¸æ³¨å†Œçš„场景。" +"节点ä¸æ³¨å†Œè‡ªå·±ï¼ˆå½“æ ‘ä¸Šè¡Œï¼‰ã€‚æ¯ä¸ªè§†å£åªèƒ½æ¿€æ´»ä¸€ä¸ªç›¸æœºã€‚å¦‚æžœåœ¨æ ‘ä¸Šæ²¡æœ‰å¯ç”¨çš„视" +"å£ï¼Œç›¸æœºå°†åœ¨å…¨å±€è§†å£ä¸æ³¨å†Œã€‚æ¢å¥è¯è¯´ï¼Œç›¸æœºåªæ˜¯ä¸º [Viewport] æä¾› 3D 显示能" +"åŠ›ï¼Œå¦‚æžœæ²¡æœ‰ï¼Œåˆ™æ— æ³•æ˜¾ç¤ºåœ¨è¯¥ [Viewport] 或更高视å£ä¸æ³¨å†Œçš„场景。" #: doc/classes/Camera.xml msgid "" @@ -14720,7 +14743,7 @@ msgid "" "[/codeblock]" msgstr "" "返回 [Viewport] 矩形ä¸çš„ 2D åæ ‡ï¼Œè¯¥åæ ‡æ˜ å°„åˆ°ä¸–ç•Œç©ºé—´ä¸ç»™å®šçš„ 3D 点。\n" -"[b]注æ„:[/b]当使用它æ¥å®šä½ 3D 视区上的 GUI å…ƒç´ æ—¶ï¼Œå¦‚æžœ 3D 点在相机åŽé¢ï¼Œè¯·" +"[b]注æ„:[/b]当使用它æ¥å®šä½ 3D 视å£ä¸Šçš„ GUI å…ƒç´ æ—¶ï¼Œå¦‚æžœ 3D 点在相机åŽé¢ï¼Œè¯·" "使用 [method is_position_behind] æ¥é˜²æ¢å®ƒä»¬æ˜¾ç¤ºã€‚\n" "[codeblock]\n" "# 这个代ç å—是继承自 Spatial 的脚本的一部分。\n" @@ -14768,7 +14791,7 @@ msgstr "" "[code]_process[/code] 方法ä¸çš„å˜åŒ–。多普勒效果åªå¯¹ [member " "AudioStreamPlayer3D.doppler_tracking] 设置为 [constant AudioStreamPlayer3D." "DOPPLER_TRACKING_DISABLED] 以外的值的 [AudioStreamPlayer3D] 节点进行模拟。\n" -"[b]注æ„:[/b]è¦åœ¨ç¼–辑器ä¸åˆ‡æ¢å¤šæ™®å‹’效果预览,使用 3D 视区左上角的é€è§†èœå•ï¼Œå¹¶" +"[b]注æ„:[/b]è¦åœ¨ç¼–辑器ä¸åˆ‡æ¢å¤šæ™®å‹’效果预览,使用 3D 视å£å·¦ä¸Šè§’çš„é€è§†èœå•ï¼Œå¹¶" "切æ¢ä¸º[b]å¯ç”¨å¤šæ™®å‹’[/b]。" #: doc/classes/Camera.xml @@ -14816,7 +14839,7 @@ msgstr "" #: doc/classes/Camera.xml msgid "The horizontal (X) offset of the camera viewport." -msgstr "相机视窗的水平(X)å移é‡ã€‚" +msgstr "相机视å£çš„水平(X)å移é‡ã€‚" #: doc/classes/Camera.xml msgid "" @@ -14852,7 +14875,7 @@ msgstr "" #: doc/classes/Camera.xml msgid "The vertical (Y) offset of the camera viewport." -msgstr "相机视窗的垂直(Y)å移é‡ã€‚" +msgstr "相机视å£çš„垂直(Y)å移é‡ã€‚" #: doc/classes/Camera.xml msgid "" @@ -15023,7 +15046,7 @@ msgstr "" msgid "" "Make this the current 2D camera for the scene (viewport and layer), in case " "there are many cameras in the scene." -msgstr "使之æˆä¸ºè¯¥åœºæ™¯ï¼ˆè§†åŒºå’Œå›¾å±‚ï¼‰çš„å½“å‰ 2D 相机,以防场景ä¸æœ‰å¾ˆå¤šç›¸æœºã€‚" +msgstr "使之æˆä¸ºè¯¥åœºæ™¯ï¼ˆè§†å£å’Œå›¾å±‚ï¼‰çš„å½“å‰ 2D 相机,以防场景ä¸æœ‰å¾ˆå¤šç›¸æœºã€‚" #: doc/classes/Camera2D.xml msgid "" @@ -15070,7 +15093,7 @@ msgid "" "or not a [Viewport], uses the default viewport instead." msgstr "" "连接到 [Camera2D] 的自定义 [Viewport] 节点。如果为 [code]null[/code] 或者ä¸" -"是 [Viewport],则使用默认的视区。" +"是 [Viewport],则使用默认的视å£ã€‚" #: doc/classes/Camera2D.xml msgid "" @@ -15883,11 +15906,11 @@ msgstr "返回æ¤é¡¹ç›®çš„å˜æ¢çŸ©é˜µã€‚" #: doc/classes/CanvasItem.xml msgid "Returns the viewport's boundaries as a [Rect2]." -msgstr "以 [Rect2] å½¢å¼è¿”回视区的边界。" +msgstr "以 [Rect2] å½¢å¼è¿”回视å£çš„边界。" #: doc/classes/CanvasItem.xml msgid "Returns this item's transform in relation to the viewport." -msgstr "返回这个项目相对于视区的å˜æ¢ã€‚" +msgstr "返回这个项目相对于视å£çš„å˜æ¢ã€‚" #: doc/classes/CanvasItem.xml msgid "Returns the [World2D] where this item is in." @@ -16281,7 +16304,7 @@ msgid "" "Together with [member follow_viewport_scale] it can be used for a pseudo 3D " "effect." msgstr "" -"å¯ç”¨æ—¶ï¼Œè¯¥ [CanvasLayer] 会使用视区的å˜æ¢ï¼Œæ‰€ä»¥å®ƒä¼šéšç›¸æœºç§»åŠ¨ï¼Œè€Œä¸æ˜¯ä¿æŒåœ¨å±" +"å¯ç”¨æ—¶ï¼Œè¯¥ [CanvasLayer] 会使用视å£çš„å˜æ¢ï¼Œæ‰€ä»¥å®ƒä¼šéšç›¸æœºç§»åŠ¨ï¼Œè€Œä¸æ˜¯ä¿æŒåœ¨å±" "幕上的æŸä¸ªå›ºå®šä½ç½®ã€‚\n" "与 [member follow_viewport_scale] é…åˆå¯ä»¥å®žçŽ°ä¼ª 3D 效果。" @@ -19193,7 +19216,7 @@ msgid "" msgstr "" "åŠ è½½æŒ‡å®šä¸ºå‚æ•°çš„é…置文件。解æžæ–‡ä»¶çš„å†…å®¹å¹¶å°†å…¶åŠ è½½åˆ°è°ƒç”¨è¯¥æ–¹æ³•çš„ " "[ConfigFile] 对象ä¸ã€‚\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19204,7 +19227,7 @@ msgid "" msgstr "" "åŠ è½½æŒ‡å®šä¸ºå‚æ•°çš„åŠ å¯†é…置文件,使用æ供的 [code]key[/code] 对其解密。解æžæ–‡ä»¶" "çš„å†…å®¹å¹¶å°†å…¶åŠ è½½åˆ°è°ƒç”¨è¯¥æ–¹æ³•çš„ [ConfigFile] 对象ä¸ã€‚\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19215,7 +19238,7 @@ msgid "" msgstr "" "åŠ è½½ä½œä¸ºå‚æ•°çš„åŠ å¯†é…置文件,使用æ供的 [code]password[/code] 解密。该文件的内" "容被解æžå¹¶åŠ 载到调用该方法的 [ConfigFile] 对象ä¸ã€‚\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19225,7 +19248,7 @@ msgid "" msgstr "" "å°†ä¼ é€’çš„å—符串解æžä¸ºé…置文件的内容。该å—符串被解æžå¹¶åŠ 载到调用该方法的 " "ConfigFile 对象ä¸ã€‚\n" -"返回 [enum Error] 常é‡ä¹‹ä¸€ï¼ŒæˆåŠŸæ—¶è¿”回 [code]OK[/code]。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19235,7 +19258,7 @@ msgid "" msgstr "" "å°† [ConfigFile] 对象的内容ä¿å˜åˆ°æŒ‡å®šä¸ºå‚数的文件ä¸ã€‚输出文件使用 INI æ ·å¼çš„结" "构。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19246,7 +19269,7 @@ msgid "" msgstr "" "使用æ供的 [code]key[/code] å°† [ConfigFile] 对象的内容ä¿å˜åˆ°ä½œä¸ºå‚数指定的 " "AES-256 åŠ å¯†æ–‡ä»¶ä¸ã€‚输出文件使用 INI æ ·å¼çš„结构。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19257,7 +19280,7 @@ msgid "" msgstr "" "å°† [ConfigFile] 对象的内容ä¿å˜åˆ°ä½œä¸ºå‚数指定的 AES-256 åŠ å¯†æ–‡ä»¶ä¸ï¼Œä½¿ç”¨æä¾›" "çš„ [code]password[/code]è¿›è¡ŒåŠ å¯†ã€‚è¾“å‡ºæ–‡ä»¶ä½¿ç”¨ INI é£Žæ ¼çš„ç»“æž„ã€‚\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/ConfigFile.xml msgid "" @@ -19380,7 +19403,7 @@ msgid "" "code] methods provided by this class." msgstr "" "所有 UI 相关节点的基类。[Control] 具有定义其范围的边界矩形ã€ç›¸å¯¹äºŽå…¶çˆ¶æŽ§ä»¶æˆ–" -"当å‰è§†çª—的锚点ä½ç½®ä»¥åŠè¡¨ç¤ºé”šç‚¹å移的边è·ã€‚当节点ã€å…¶ä»»ä½•çˆ¶èŠ‚点或å±å¹•å°ºå¯¸å‘生" +"当å‰è§†å£çš„锚点ä½ç½®ä»¥åŠè¡¨ç¤ºé”šç‚¹å移的边è·ã€‚当节点ã€å…¶ä»»ä½•çˆ¶èŠ‚点或å±å¹•å°ºå¯¸å‘生" "å˜åŒ–时,边è·ä¼šè‡ªåŠ¨æ›´æ–°ã€‚\n" "更多关于 Godot çš„ UI 系统ã€é”šç‚¹ã€è¾¹è·å’Œå®¹å™¨çš„ä¿¡æ¯ï¼Œè¯·å‚阅手册ä¸çš„相关教程。è¦" "构建çµæ´»çš„ UI,您需è¦æ··åˆä½¿ç”¨ä»Ž [Control] å’Œ [Container] 节点继承的 UI å…ƒ" @@ -19557,8 +19580,8 @@ msgid "" "propagating, even to nodes listening to [method Node._unhandled_input] or " "[method Node._unhandled_key_input]." msgstr "" -"å°†è¾“å…¥äº‹ä»¶æ ‡è®°ä¸ºå·²å¤„ç†ã€‚一旦接å—输入事件,它就会åœæ¢ä¼ æ’ï¼Œç”šè‡³ä¼ æ’到æ£åœ¨ä¾¦å¬" -"[method Node._unhandled_input]或[method Node._unhandled_key_input]的节点。" +"å°†è¾“å…¥äº‹ä»¶æ ‡è®°ä¸ºå·²å¤„ç†ã€‚一旦接å—è¾“å…¥äº‹ä»¶ï¼Œä¼ æ’就会åœæ¢ï¼Œä¸ä¼šå†ä¼ æ’到æ£åœ¨ä¾¦å¬ " +"[method Node._unhandled_input] å’Œ [method Node._unhandled_key_input] 的节点。" #: doc/classes/Control.xml msgid "" @@ -20647,7 +20670,7 @@ msgid "" "handled." msgstr "" "å…³é—模æ€æŽ§ä»¶æ—¶ï¼Œè¾“入是å¦ä¼ æ’。\n" -"如果为 [code]false[/code],事件处ç†å°†åœæ¢åœ¨è§†åŒºçš„输入事件处ç†ã€‚该视区会先将模" +"如果为 [code]false[/code],事件处ç†å°†åœæ¢åœ¨è§†å£çš„输入事件处ç†ã€‚该视å£ä¼šå…ˆå°†æ¨¡" "æ€æŽ§ä»¶éšè—,然åŽå†å°†è¾“å…¥æ ‡è®°ä¸ºå·²å¤„ç†ã€‚" #: doc/classes/Control.xml @@ -20800,7 +20823,7 @@ msgstr "" "这个值进行缩放。\n" "[b]注æ„:[/b]这个属性主è¦ç”¨äºŽåŠ¨ç”»ç”¨é€”。当控件被缩放时,控件内的文本将看起æ¥æ˜¯" "åƒç´ 化或模糊的。è¦åœ¨ä½ 的项目支æŒå¤šç§åˆ†è¾¨çŽ‡ï¼Œè¯·ä½¿ç”¨[url=$DOCS_URL/tutorials/" -"rendering/multiple_resolutions.html]文档[/url]ä¸æè¿°çš„åˆé€‚的视窗拉伸模å¼ï¼Œè€Œ" +"rendering/multiple_resolutions.html]文档[/url]ä¸æè¿°çš„åˆé€‚的视å£æ‹‰ä¼¸æ¨¡å¼ï¼Œè€Œ" "ä¸æ˜¯å•ç‹¬ç¼©æ”¾æŽ§ä»¶ã€‚\n" "[b]注æ„:[/b]如果控件节点是 [Container] 节点的å节点,当场景实例化时,缩放将" "被é‡ç½®ä¸º [code]Vector2(1, 1)[/code]。è¦åœ¨å®žä¾‹åŒ–时设置控件的缩放,使用 " @@ -24076,7 +24099,7 @@ msgstr "" #: doc/classes/CylinderShape.xml msgid "Cylinder shape for collisions." -msgstr "碰撞用的圆柱体形状。" +msgstr "用于碰撞的圆柱体形状。" #: doc/classes/CylinderShape.xml msgid "" @@ -24085,6 +24108,9 @@ msgid "" "engine, there are several known bugs with cylinder collision shapes. Using " "[CapsuleShape] or [BoxShape] instead is recommended." msgstr "" +"用于碰撞的圆柱体形状。\n" +"[b]注æ„:[/b]使用 GodotPhysics 而éžé»˜è®¤çš„ Bullet 物ç†å¼•æ“Žæ—¶ï¼Œåœ†æŸ±ä½“碰撞形状å˜" +"在已知的问题。推è使用 [CapsuleShape] 或 [BoxShape] 代替。" #: doc/classes/CylinderShape.xml msgid "The cylinder's height." @@ -24665,7 +24691,7 @@ msgstr "" "将当å‰æ‰“开的目录改为å‚æ•°ä¼ é€’çš„ç›®å½•ã€‚å‚æ•°å¯ä»¥æ˜¯ç›¸å¯¹äºŽå½“å‰ç›®å½•çš„(例如 " "[code]newdir[/code] 或 [code].../newdir[/code]),也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„(例如 " "[code]/tmp/newdir[/code] 或 [code]res://somedir/newdir[/code])。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆ[code]OK[/code] æˆåŠŸæ—¶ï¼‰ã€‚" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/Directory.xml msgid "" @@ -24677,7 +24703,7 @@ msgid "" msgstr "" "å°† [code]from[/code] 文件å¤åˆ¶åˆ° [code]to[/code] ç›®æ ‡ä½ç½®ã€‚两个å‚数都应该是相" "对或ç»å¯¹æ–‡ä»¶çš„è·¯å¾„ã€‚å¦‚æžœç›®æ ‡æ–‡ä»¶å˜åœ¨ä¸”没有访问ä¿æŠ¤ï¼Œåˆ™ä¼šè¢«è¦†ç›–。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/Directory.xml msgid "" @@ -24685,8 +24711,8 @@ msgid "" "call is a directory ([code].[/code] and [code]..[/code] are considered " "directories)." msgstr "" -"返回上一次 [method get_next] 调用处ç†çš„当å‰é¡¹ç›®æ˜¯å¦ä¸ºç›®å½•ï¼ˆ[code].[/code]å’Œ" -"[code].[/code]被认为是目录)。" +"返回上一次 [method get_next] 调用处ç†çš„当å‰é¡¹ç›®æ˜¯å¦ä¸ºç›®å½•ï¼ˆ[code].[/code] å’Œ " +"[code].[/code] 属于目录)。" #: doc/classes/Directory.xml msgid "" @@ -24707,16 +24733,16 @@ msgid "" "Returns the absolute path to the currently opened directory (e.g. " "[code]res://folder[/code] or [code]C:\\tmp\\folder[/code])." msgstr "" -"返回当å‰æ‰“开目录的ç»å¯¹è·¯å¾„(例如[code]res://文件夹[/code]或[code]C:\\tmp\\æ–‡" -"件夹[/code])。" +"返回当å‰æ‰“开目录的ç»å¯¹è·¯å¾„(例如 [code]res://文件夹[/code] 或 [code]C:" +"\\tmp\\文件夹[/code])。" #: doc/classes/Directory.xml msgid "" "Returns the currently opened directory's drive index. See [method get_drive] " "to convert returned index to the name of the drive." msgstr "" -"返回当å‰æ‰“开的目录的驱动器索引。请å‚阅[method get_drive]将返回的索引转æ¢ä¸ºé©±" -"动器的å称。" +"返回当å‰æ‰“开的目录的驱动器索引。请å‚阅 [method get_drive] 将返回的索引转æ¢ä¸º" +"驱动器的å称。" #: doc/classes/Directory.xml msgid "" @@ -24757,11 +24783,12 @@ msgid "" "closes the stream automatically (i.e. [method list_dir_end] would not be " "mandatory in such a case)." msgstr "" -"返回当å‰ç›®å½•ä¸çš„ä¸‹ä¸€ä¸ªå…ƒç´ ï¼ˆæ–‡ä»¶æˆ–ç›®å½•ï¼‰ï¼ˆåŒ…æ‹¬[code].[/code]å’Œ[code].[/" -"code],除éž[code]skip_navigational[/code]被赋予[method list_dir_begin])。\n" +"返回当å‰ç›®å½•ä¸çš„ä¸‹ä¸€ä¸ªå…ƒç´ ï¼ˆæ–‡ä»¶æˆ–ç›®å½•ã€‚é™¤éžå°† [code]skip_navigational[/" +"code] 赋予 [method list_dir_begin],å¦åˆ™åŒ…括 [code].[/code] å’Œ [code].[/" +"code])。\n" "返回的是文件或目录的å称(而ä¸æ˜¯å®ƒçš„完整路径)。一旦æµè¢«å®Œå…¨å¤„ç†ï¼Œè¯¥æ–¹æ³•è¿”回" -"一个空的String,并自动关é—æµï¼ˆå³åœ¨è¿™ç§æƒ…况下,[method list_dir_end]å°†ä¸æ˜¯å¼ºåˆ¶" -"性的)。" +"一个空的 String,并自动关é—æµï¼ˆå³åœ¨è¿™ç§æƒ…况下,[method list_dir_end] å°†ä¸æ˜¯å¼º" +"制性的)。" #: doc/classes/Directory.xml msgid "" @@ -24808,7 +24835,7 @@ msgstr "" "创建一个目录。å‚æ•°å¯ä»¥æ˜¯å½“å‰ç›®å½•çš„相对路径,也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„ã€‚ç›®æ ‡ç›®å½•åº”è¯¥æ”¾" "置在一个已ç»å˜åœ¨çš„目录ä¸ï¼ˆå¦‚æžœè¦é€’归创建完整的路径,请å‚阅 [method " "make_dir_recursive])。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/Directory.xml msgid "" @@ -24817,9 +24844,9 @@ msgid "" "to the current directory, or an absolute path.\n" "Returns one of the [enum Error] code constants ([code]OK[/code] on success)." msgstr "" -"通过递归调用 [method make_dir]æ–¹æ³•ï¼Œåˆ›å»ºä¸€ä¸ªç›®æ ‡ç›®å½•å’Œå…¶è·¯å¾„ä¸æ‰€æœ‰å¿…è¦çš„ä¸é—´" +"通过递归调用 [method make_dir] æ–¹æ³•ï¼Œåˆ›å»ºä¸€ä¸ªç›®æ ‡ç›®å½•å’Œå…¶è·¯å¾„ä¸æ‰€æœ‰å¿…è¦çš„ä¸é—´" "目录。å‚æ•°å¯ä»¥æ˜¯ç›¸å¯¹äºŽå½“å‰ç›®å½•çš„,也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/Directory.xml msgid "" @@ -24833,7 +24860,7 @@ msgstr "" "folder[/code]),用户目录([code]user:// folder[/code])或以下ä½ç½®çš„ç»å¯¹è·¯å¾„" "内:用户文件系统(例如 [code]/tmp/folder[/code] 或 [code]C:\\tmp\\folder[/" "code])。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/Directory.xml msgid "" @@ -24847,7 +24874,7 @@ msgstr "" "æ°¸ä¹…åˆ é™¤ç›®æ ‡æ–‡ä»¶æˆ–ç©ºç›®å½•ã€‚å‚æ•°å¯ä»¥æ˜¯ç›¸å¯¹äºŽå½“å‰ç›®å½•çš„,也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„。如果" "ç›®æ ‡ç›®å½•ä¸æ˜¯ç©ºçš„,æ“作将失败。\n" "å¦‚æžœä½ ä¸æƒ³æ°¸ä¹…åˆ é™¤è¯¥æ–‡ä»¶/目录,请使用 [method OS.move_to_trash] 代替。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/Directory.xml msgid "" @@ -24860,7 +24887,7 @@ msgstr "" "å°† [code]from[/code] 文件或目录é‡å‘½å且移动到 [code]to[/code] ç›®æ ‡ã€‚ä¸¤ä¸ªå‚æ•°" "都应该是文件或目录的相对路径或ç»å¯¹è·¯å¾„ã€‚å¦‚æžœç›®æ ‡æ–‡ä»¶æˆ–ç›®å½•å˜åœ¨ä¸”ä¸å—访问ä¿" "护,它将被覆盖。\n" -"返回 [enum Error] 代ç 常é‡ä¹‹ä¸€ï¼ŒæˆåŠŸæ—¶è¿”回 [code]OK[/code]。" +"返回 [enum Error] 错误ç 常é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。" #: doc/classes/DTLSServer.xml msgid "Helper class to implement a DTLS server." @@ -25127,7 +25154,7 @@ msgid "" "This can be a negative number to make the distance between words smaller." msgstr "" "ç©ºæ ¼å—符(在 [member extra_spacing_char] 之外)的é¢å¤–é—´è·ï¼Œå•ä½ä¸ºåƒç´ 。\n" -"è¿™å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä½¿å—符之间的è·ç¦»æ›´å°ã€‚" +"å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä¼šä½¿å—符之间的è·ç¦»æ›´å°ã€‚" #: doc/classes/DynamicFont.xml msgid "Extra spacing at the top in pixels." @@ -25166,9 +25193,9 @@ msgid "" "control whose size changes over time, unless a pixel art aesthetic is " "desired." msgstr "" -"如果为 [code]true[/code],将使用过滤功能。如果å—ä½“è¿‡åº¦é‡‡æ ·è¢«ç¦ç”¨æˆ–æ— æ•ˆï¼Œè¿™å°†" -"使å—体在缩放时å˜å¾—模糊,而éžåƒç´ 化。当在尺寸éšæ—¶å˜åŒ–的控件ä¸ä½¿ç”¨å—体时,建议" -"å¯ç”¨è¿™ä¸ªåŠŸèƒ½ï¼Œé™¤éžæ˜¯åƒç´ 设计。" +"如果为 [code]true[/code],将使用过滤功能。如果å—ä½“è¿‡é‡‡æ ·è¢«ç¦ç”¨æˆ–æ— æ³•ç”Ÿæ•ˆï¼Œå—" +"体在缩放时会å˜å¾—模糊,而éžåƒç´ 化。在尺寸会éšæ—¶å˜åŒ–的控件ä¸ä½¿ç”¨å—体时,建议å¯" +"用这个功能,除éžæƒ³è¦åƒç´ ç”»é£Žæ ¼ã€‚" #: doc/classes/DynamicFont.xml msgid "" @@ -25176,8 +25203,8 @@ msgid "" "appearance when downscaling it if font oversampling is disabled or " "ineffective." msgstr "" -"如果为 [code]true[/code],将使用 mipmap 多级æ¸è¿œçº¹ç†ã€‚在å—ä½“è¿‡åº¦é‡‡æ ·è¢«ç¦ç”¨æˆ–" -"æ— æ•ˆæ—¶ï¼Œå¯æ”¹å–„å—体缩å°æ—¶çš„表现。" +"如果为 [code]true[/code],将使用 mipmap 多级æ¸è¿œçº¹ç†ã€‚在å—ä½“è¿‡é‡‡æ ·è¢«ç¦ç”¨æˆ–æ— " +"法生效时,å¯æ”¹å–„å—体缩å°æ—¶çš„表现。" #: doc/classes/DynamicFont.xml msgid "Spacing at the top." @@ -25229,7 +25256,7 @@ msgid "" "and viewport stretch mode." msgstr "" "如果设为比 [code]0.0[/code] 大的值,则会覆盖默认的å—ä½“è¿‡é‡‡æ ·ï¼Œå¿½ç•¥ [member " -"SceneTree.use_font_oversampling] 的值和视å£æ‹‰ä¼¸æ¨¡å¼ã€‚" +"SceneTree.use_font_oversampling] 的值和视å£çš„拉伸模å¼ã€‚" #: doc/classes/DynamicFontData.xml msgid "Disables font hinting (smoother but less crisp)." @@ -26338,7 +26365,7 @@ msgstr "" "æ–°ï¼‰åŠ è½½åœºæ™¯ï¼Œæ¸²æŸ“ç½‘æ ¼é¢„è§ˆï¼Œæ£€æŸ¥å’Œç¼–è¾‘èµ„æºå’Œå¯¹è±¡ã€‚它å…许自定义窗å£ï¼Œä¿å˜å’Œ" "(é‡æ–°ï¼‰åŠ è½½åœºæ™¯ï¼Œæ¸²æŸ“ç½‘æ ¼é¢„è§ˆï¼Œæ£€æŸ¥å’Œç¼–è¾‘èµ„æºå’Œå¯¹è±¡ï¼Œå¹¶æ供对 " "[EditorSettings]ã€[EditorFileSystem]ã€[EditorResourcePreview]ã€" -"[ScriptEditor]ã€ç¼–辑器视窗和场景信æ¯çš„访问。\n" +"[ScriptEditor]ã€ç¼–辑器视å£å’Œåœºæ™¯ä¿¡æ¯çš„访问。\n" "[b]注æ„:[/b]这个类ä¸åº”该直接实例化。相å,使用 [method EditorPlugin." "get_editor_interface] 访问å•ä¾‹ã€‚" @@ -26414,7 +26441,7 @@ msgid "" msgstr "" "返回主编辑器控件。将其作为主å±å¹•çš„父控件。\n" "[b]注æ„:[/b]这将返回包å«æ•´ä¸ªç¼–辑器的主编辑器控件,而ä¸æ˜¯å…·ä½“çš„ 2D或 3D 视" -"窗。\n" +"å£ã€‚\n" "[b]è¦å‘Šï¼š[/b]åˆ é™¤å’Œé‡Šæ”¾è¿™ä¸ªèŠ‚ç‚¹å°†ä½¿ç¼–è¾‘å™¨çš„ä¸€éƒ¨åˆ†å¤±åŽ»ä½œç”¨ï¼Œå¹¶å¯èƒ½å¯¼è‡´å´©æºƒã€‚" #: doc/classes/EditorInterface.xml @@ -26734,7 +26761,7 @@ msgid "" "custom gizmos to the 3D preview viewport for a [Spatial].\n" "See [method add_inspector_plugin] for an example of how to register a plugin." msgstr "" -"注册一个新的 [EditorSpatialGizmoPlugin]。å°å·¥å…·æ’件å¯ä»¥åœ¨ 3D 预览视区ä¸ä¸º " +"注册一个新的 [EditorSpatialGizmoPlugin]。å°å·¥å…·æ’件å¯ä»¥åœ¨ 3D 预览视å£ä¸ä¸º " "[Spatial] æ·»åŠ è‡ªå®šä¹‰çš„å°å·¥å…·ã€‚\n" "注册æ’ä»¶çš„ç¤ºä¾‹è§ [method add_inspector_plugin]。" @@ -26830,8 +26857,8 @@ msgid "" " return false\n" "[/codeblock]" msgstr "" -"引擎会在 2D 编辑器的视区å‘生更新时调用。使用 [code]overlay[/code] [Control] " -"è¿›è¡Œç»˜åˆ¶ã€‚ä½ å¯ä»¥é€šè¿‡è°ƒç”¨ [method update_overlays] 手动更新视窗。\n" +"引擎会在 2D 编辑器的视å£å‘生更新时调用。使用 [code]overlay[/code] [Control] " +"è¿›è¡Œç»˜åˆ¶ã€‚ä½ å¯ä»¥é€šè¿‡è°ƒç”¨ [method update_overlays] 手动更新视å£ã€‚\n" "[codeblock]\n" "func forward_canvas_draw_over_viewport(overlay):\n" " # åœ¨å…‰æ ‡ä½ç½®ç”»ä¸€ä¸ªåœ†ã€‚\n" @@ -26840,7 +26867,7 @@ msgstr "" "\n" "func forward_canvas_gui_input(event):\n" " if event is InputEventMouseMotion:\n" -" # å½“å…‰æ ‡è¢«ç§»åŠ¨æ—¶ï¼Œé‡ç»˜è§†çª—。\n" +" # å½“å…‰æ ‡è¢«ç§»åŠ¨æ—¶ï¼Œé‡ç»˜è§†å£ã€‚\n" " update_overlays()\n" " return true\n" " return false\n" @@ -26883,7 +26910,7 @@ msgid "" " return forward\n" "[/codeblock]" msgstr "" -"当当å‰ç¼–辑场景ä¸æœ‰ä¸€ä¸ªæ ¹èŠ‚点时被调用,[method handles]实现,在2D视窗ä¸å‘生按" +"当当å‰ç¼–辑场景ä¸æœ‰ä¸€ä¸ªæ ¹èŠ‚点时被调用,[method handles]实现,在2D视å£ä¸å‘生按" "键输入[InputEvent]。拦截按键输入[InputEvent],如果[code]return true[/code] " "[EditorPlugin]消耗键值[code]event[/code],å¦åˆ™å°†é”®å€¼[code]event[/code]转å‘ç»™" "其他Editor类。例å:\n" @@ -26922,9 +26949,9 @@ msgid "" " return false\n" "[/codeblock]" msgstr "" -"引擎会在 3D 编辑器的视区å‘生更新时调用。使用 [code]overlay[/code] 控件 " +"引擎会在 3D 编辑器的视å£å‘生更新时调用。使用 [code]overlay[/code] 控件 " "[Control] è¿›è¡Œç»˜åˆ¶ã€‚ä½ å¯ä»¥é€šè¿‡è°ƒç”¨ [method update_overlays] 更新覆盖手动更新" -"视窗。\n" +"视å£ã€‚\n" "[codeblock]\n" "func forward_spatial_draw_over_viewport(overlay):\n" " # åœ¨å…‰æ ‡ä½ç½®ç”»ä¸€ä¸ªåœ†ã€‚\n" @@ -26932,7 +26959,7 @@ msgstr "" "\n" "func forward_spatial_gui_input(camera, event):\n" " if event is InputEventMouseMotion:\n" -" # å½“å…‰æ ‡è¢«ç§»åŠ¨æ—¶ï¼Œé‡ç»˜è§†çª—。\n" +" # å½“å…‰æ ‡è¢«ç§»åŠ¨æ—¶ï¼Œé‡ç»˜è§†å£ã€‚\n" " update_overlays()\n" " return true\n" " return false\n" @@ -26975,7 +27002,7 @@ msgid "" " return forward\n" "[/codeblock]" msgstr "" -"在当å‰ç¼–辑的场景ä¸å˜åœ¨æ ¹èŠ‚点时调用,实现[method handles]并在3D视窗ä¸å‘生按键" +"在当å‰ç¼–辑的场景ä¸å˜åœ¨æ ¹èŠ‚点时调用,实现[method handles]并在3D视å£ä¸å‘生按键" "输入[InputEvent]。拦截按键输入[InputEvent],如果[code]return true[/code],则" "[EditorPlugin]会使用键值[code]event[/code],å¦åˆ™å°†é”®å€¼[code]event[/code]转å‘" "到其他Editor类。例å:\n" @@ -27245,7 +27272,7 @@ msgid "" "once and it will work permanently for this plugin." msgstr "" "å¯ç”¨ 2D 编辑器的 [method forward_canvas_force_draw_over_viewport] å’Œ 3D 编辑" -"器的 [method forward_spatial_force_draw_over_viewport] 在其视窗更新时的调用。" +"器的 [method forward_spatial_force_draw_over_viewport] 在其视å£æ›´æ–°æ—¶çš„调用。" "ä½ åªéœ€è¦è°ƒç”¨è¿™ä¸ªæ–¹æ³•ä¸€æ¬¡ï¼Œå®ƒå°±ä¼šå¯¹è¿™ä¸ªæ’件永久起作用。" #: doc/classes/EditorPlugin.xml @@ -27312,7 +27339,7 @@ msgid "" "forward_spatial_draw_over_viewport] and [method " "forward_spatial_force_draw_over_viewport] to be called." msgstr "" -"æ›´æ–° 2D å’Œ 3D 编辑器视窗的覆盖层。导致方法 [method " +"æ›´æ–° 2D å’Œ 3D 编辑器视å£çš„覆盖层。导致方法 [method " "forward_canvas_draw_over_viewport]ã€[method " "forward_canvas_force_draw_over_viewport]ã€[method " "forward_spatial_draw_over_viewport] å’Œ [method " @@ -27890,7 +27917,6 @@ msgid "Base script that can be used to add extension functions to the editor." msgstr "å¯ç”¨äºŽä¸ºç¼–è¾‘å™¨æ·»åŠ æ‰©å±•åŠŸèƒ½çš„åŸºç¡€è„šæœ¬ã€‚" #: doc/classes/EditorScript.xml -#, fuzzy msgid "" "Scripts extending this class and implementing its [method _run] method can " "be executed from the Script Editor's [b]File > Run[/b] menu option (or by " @@ -27927,7 +27953,9 @@ msgstr "" " print(\"Hello from the Godot Editor!\")\n" "[/codeblock]\n" "[b]注æ„:[/b]脚本在编辑器上下文ä¸è¿è¡Œï¼Œè¿™æ„味ç€è¾“出在与编辑器一起å¯åŠ¨çš„控制å°" -"窗å£ï¼ˆstdout),而ä¸æ˜¯é€šå¸¸çš„ Godot [b]输出[/b]é¢æ¿ 。" +"窗å£ï¼ˆstdout),而ä¸æ˜¯é€šå¸¸çš„ Godot [b]输出[/b]é¢æ¿ 。\n" +"[b]注æ„:[/b]EditorScript 进行了引用计数,ä¸å†è¢«å¼•ç”¨æ—¶å°±ä¼šè¢«é”€æ¯ã€‚在进行异æ¥" +"æ“作时,如果ä¸å†å˜åœ¨å¯¹è¯¥è„šæœ¬çš„引用,就å¯èƒ½é€ æˆé”™è¯¯ã€‚" #: doc/classes/EditorScript.xml msgid "This method is executed by the Editor when [b]File > Run[/b] is used." @@ -37769,6 +37797,7 @@ msgstr "" "[b]注æ„:[/b]这个值在 Android å’Œ iOS 上å¯ç«‹å³è¢«ç¡¬ä»¶ä¼ 感器的值所覆盖。" #: doc/classes/Input.xml +#, fuzzy msgid "" "Sets a custom mouse cursor image, which is only visible inside the game " "window. The hotspot can also be specified. Passing [code]null[/code] to the " @@ -37780,7 +37809,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" "è®¾ç½®ä¸€ä¸ªè‡ªå®šä¹‰é¼ æ ‡å…‰æ ‡å›¾åƒï¼Œè¯¥å›¾åƒä»…当游æˆçª—å£å†…å¯è§ã€‚还å¯ä»¥æŒ‡å®šçƒç‚¹ã€‚å°† " "[code]null[/code] ä¼ é€’ç»™ image å‚æ•°å°†é‡ç½®ä¸ºç³»ç»Ÿå…‰æ ‡ã€‚有关详细信æ¯ï¼Œè¯·å‚阅 " @@ -37801,7 +37834,7 @@ msgid "" "[b]Note:[/b] This method generates an [InputEventMouseMotion] to update " "cursor immediately." msgstr "" -"设置该视区ä¸ä½¿ç”¨çš„é»˜è®¤å…‰æ ‡å½¢çŠ¶ï¼Œè€Œä¸æ˜¯ [constant CURSOR_ARROW]。\n" +"设置该视å£ä¸ä½¿ç”¨çš„é»˜è®¤å…‰æ ‡å½¢çŠ¶ï¼Œè€Œä¸æ˜¯ [constant CURSOR_ARROW]。\n" "[b]注æ„:[/b]如果è¦æ›´æ”¹ [Control] èŠ‚ç‚¹çš„é»˜è®¤å…‰æ ‡å½¢çŠ¶ï¼Œè¯·æ”¹ç”¨ [member Control." "mouse_default_cursor_shape]。\n" "[b]注æ„:[/b]这个方法会生æˆä¸€ä¸ª [InputEventMouseMotion] 以立å³æ›´æ–°å…‰æ ‡ã€‚" @@ -41529,7 +41562,6 @@ msgstr "" "如果为 [code]true[/code],则光线的效果会逆转,使区域å˜æš—并投射明亮的阴影。" #: doc/classes/Light.xml -#, fuzzy msgid "" "The size of the light in Godot units. Only considered in baked lightmaps and " "only if [member light_bake_mode] is set to [constant BAKE_ALL]. Increasing " @@ -41540,7 +41572,9 @@ msgid "" msgstr "" "ç¯å…‰çš„大å°ï¼Œä½¿ç”¨ Godot çš„å•ä½ã€‚åªåœ¨çƒ˜ç„™çš„光照贴图ä¸è€ƒè™‘,并且åªåœ¨ [member " "light_bake_mode] 被设置为 [constant BAKE_ALL] æ—¶è€ƒè™‘ã€‚å¢žåŠ è¿™ä¸ªå€¼ä¼šä½¿é˜´å½±çœ‹èµ·" -"æ¥æ›´æ¨¡ç³Šã€‚è¿™å¯ä»¥åœ¨ä¸€å®šç¨‹åº¦ä¸Šç”¨äºŽæ¨¡æ‹ŸåŒºåŸŸç¯å…‰ã€‚" +"æ¥æ›´æ¨¡ç³Šã€‚è¿™å¯ä»¥åœ¨ä¸€å®šç¨‹åº¦ä¸Šç”¨äºŽæ¨¡æ‹ŸåŒºåŸŸç¯å…‰ã€‚\n" +"[b]注æ„:[/b][member light_size] ä¸å— [member Spatial.scale] çš„å½±å“ï¼ˆæ— è®ºæ˜¯è¯¥" +"ç¯å…‰çš„缩放还是其父节点的缩放)。" #: doc/classes/Light.xml msgid "" @@ -44044,7 +44078,7 @@ msgid "" "MeshInstance2D[/b] at the top of the 2D editor viewport." msgstr "" "用于在 2D ä¸æ˜¾ç¤º [Mesh] 的节点。å¯ä»¥é€šè¿‡ç¼–辑器工具æ 上的工具从现有的 " -"[Sprite] æž„å»ºã€‚é€‰ä¸ [Sprite] 节点,然åŽåœ¨ 2D 编辑器视区顶部选择[b]ç²¾çµ > 转æ¢" +"[Sprite] æž„å»ºã€‚é€‰ä¸ [Sprite] 节点,然åŽåœ¨ 2D 编辑器视å£é¡¶éƒ¨é€‰æ‹©[b]ç²¾çµ > 转æ¢" "为 MeshInstance2D[/b]。" #: doc/classes/MeshInstance2D.xml @@ -45547,7 +45581,6 @@ msgid "3D agent used in navigation for collision avoidance." msgstr "在导航ä¸ç”¨äºŽé˜²æ’žçš„ 3D 代ç†ã€‚" #: doc/classes/NavigationAgent.xml -#, fuzzy msgid "" "3D agent that is used in navigation to reach a location while avoiding " "static and dynamic obstacles. The dynamic obstacles are avoided using RVO " @@ -45574,7 +45607,9 @@ msgstr "" "[NavigationAgent] 是物ç†å®‰å…¨çš„。\n" "[b]注æ„:[/b]使用 [method set_target_location] 之åŽï¼Œå¿…须在æ¯ä¸ªç‰©ç†å¸§ä½¿ç”¨ä¸€" "次 [method get_next_location] 函数æ¥æ›´æ–° NavigationAgent 的内部路径逻辑。这个" -"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚" +"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚\n" +"[b]注æ„:[/b]默认情况下,é¿éšœçš„大强度计算是在å•ç‹¬çš„线程ä¸è¿›è¡Œçš„。在ä¸æ”¯æŒå¤šçº¿" +"程的 HTML5 导出ä¸ï¼Œåˆ™ä¼šåœ¨ä¸»çº¿ç¨‹ä¸è¿›è¡Œï¼Œå¯èƒ½å¯¼è‡´æ€§èƒ½é—®é¢˜ã€‚" #: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml msgid "" @@ -45867,7 +45902,6 @@ msgid "2D agent used in navigation for collision avoidance." msgstr "在导航ä¸ç”¨äºŽé˜²æ’žçš„ 2D 代ç†ã€‚" #: doc/classes/NavigationAgent2D.xml -#, fuzzy msgid "" "2D agent that is used in navigation to reach a location while avoiding " "static and dynamic obstacles. The dynamic obstacles are avoided using RVO " @@ -45894,7 +45928,9 @@ msgstr "" "[NavigationAgent2D] 是物ç†å®‰å…¨çš„。\n" "[b]注æ„:[/b]使用 [method set_target_location] 之åŽï¼Œå¿…须在æ¯ä¸ªç‰©ç†å¸§ä½¿ç”¨ä¸€" "次 [method get_next_location] 函数æ¥æ›´æ–° NavigationAgent 的内部路径逻辑。这个" -"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚" +"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚\n" +"[b]注æ„:[/b]默认情况下,é¿éšœçš„大强度计算是在å•ç‹¬çš„线程ä¸è¿›è¡Œçš„。在ä¸æ”¯æŒå¤šçº¿" +"程的 HTML5 导出ä¸ï¼Œåˆ™ä¼šåœ¨ä¸»çº¿ç¨‹ä¸è¿›è¡Œï¼Œå¯èƒ½å¯¼è‡´æ€§èƒ½é—®é¢˜ã€‚" #: doc/classes/NavigationAgent2D.xml msgid "" @@ -46763,7 +46799,6 @@ msgid "Server interface for low-level 3D navigation access." msgstr "访问底层 3D 导航的æœåŠ¡å™¨æŽ¥å£ã€‚" #: doc/classes/NavigationServer.xml -#, fuzzy msgid "" "NavigationServer is the server responsible for all 3D navigation. It handles " "several objects, namely maps, regions and agents.\n" @@ -46805,6 +46840,8 @@ msgstr "" "的速度触å‘回调。\n" "[b]注æ„:[/b]防撞系统会忽略地区。直接使用修æ£åŽçš„速度å¯èƒ½ä¼šå°†ä»£ç†æŽ¨åˆ°å¯å¯¼èˆªåŒº" "域之外。这是防撞系统的缺陷,更å¤æ‚的情况å¯èƒ½éœ€è¦ç”¨åˆ°ç‰©ç†å¼•æ“Žã€‚\n" +"[b]注æ„:[/b]默认情况下,é¿éšœçš„大强度计算是在å•ç‹¬çš„线程ä¸è¿›è¡Œçš„。在ä¸æ”¯æŒå¤šçº¿" +"程的 HTML5 导出ä¸ï¼Œåˆ™ä¼šåœ¨ä¸»çº¿ç¨‹ä¸è¿›è¡Œï¼Œå¯èƒ½å¯¼è‡´æ€§èƒ½é—®é¢˜ã€‚\n" "æœåŠ¡å™¨ä¼šè®°å½•æ‰€æœ‰çš„调用,在åŒæ¥é˜¶æ®µç»Ÿä¸€æ‰§è¡Œã€‚è¿™æ„味ç€ä½ å¯ä»¥æ”¾å¿ƒå¤§èƒ†åœ°ä»Žä»»ä½•çº¿" "程ä¸è¯·æ±‚对地图进行任何修改。" @@ -50536,9 +50573,9 @@ msgstr "" "[OccluderShape] 是 [Occluder] 节点所使用的资æºï¼Œç”¨äºŽå‡ 何é®æŒ¡å‰”除。\n" "è¯¥å¤šè¾¹å½¢å¿…é¡»æ˜¯å‡¸å¤šè¾¹å½¢ã€‚å¤šè¾¹å½¢é¡¶ç‚¹çš„åˆ›å»ºä¸Žåˆ é™¤å¯ä»¥åœ¨ç¼–辑器的检查器ä¸è¿›è¡Œï¼Œä¹Ÿ" "å¯ä»¥é€šè¿‡è°ƒç”¨ [code]set_polygon_points[/code] 实现。æ¯ä¸€æ¡è¾¹çš„顶点都å¯ä»¥é€šè¿‡åœ¨" -"编辑器视窗ä¸æ‹–拽手柄设置。\n" +"编辑器视å£ä¸æ‹–拽手柄设置。\n" "å¦å¤–,æ¯ä¸€ä¸ªå¤šè¾¹å½¢é®æŒ¡å™¨éƒ½å¯ä»¥æ”¯æŒå•ä¸ªç©ºæ´žã€‚å¦‚æžœä½ åœ¨ç¼–è¾‘å™¨çš„æ£€æŸ¥å™¨ä¸ä¸ºç©ºæ´žæ·»" -"åŠ è‡³å°‘ä¸‰ä¸ªé¡¶ç‚¹ï¼Œå°±å¯ä»¥åœ¨ç¼–辑器视窗ä¸æ‹–拽空洞边缘顶点的å¥æŸ„。\n" +"åŠ è‡³å°‘ä¸‰ä¸ªé¡¶ç‚¹ï¼Œå°±å¯ä»¥åœ¨ç¼–辑器视å£ä¸æ‹–拽空洞边缘顶点的å¥æŸ„。\n" "一般而言,多边形以åŠç©ºæ´žçš„边数越少,è¿è¡Œæ—¶ç³»ç»Ÿçš„处ç†é€Ÿåº¦å°±è¶Šå¿«ï¼Œæ‰€ä»¥åœ¨å¤§å¤šæ•°" "æƒ…å†µä¸‹ä½ éƒ½åªä¼šè®¾ç½® 4 个顶点。" @@ -50632,7 +50669,6 @@ msgstr "" "光的衰å‡ï¼ˆä¸‹é™ï¼‰æ›²çº¿ã€‚在[b]检查器[/b]ä¸ï¼Œé€šè¿‡å³é”®ç‚¹å‡»æ›²çº¿ï¼Œå¯ä»¥èŽ·å¾—许多预设。" #: doc/classes/OmniLight.xml -#, fuzzy msgid "" "The light's radius. Note that the effectively lit area may appear to be " "smaller depending on the [member omni_attenuation] in use. No matter the " @@ -50641,9 +50677,11 @@ msgid "" "[b]Note:[/b] [member omni_range] is not affected by [member Spatial.scale] " "(the light's scale or its parent's scale)." msgstr "" -"光的åŠå¾„。请注æ„,有效的照明区域å¯èƒ½çœ‹èµ·æ¥æ›´å°ï¼Œè¿™å–决于使用的 [member " -"omni_attenuation]ã€‚æ— è®ºä½¿ç”¨ä½•ç§ [member omni_attenuation],光线都ä¸ä¼šåˆ°è¾¾è¿™ä¸ª" -"åŠå¾„以外的地方。" +"该ç¯å…‰çš„åŠå¾„。请注æ„ï¼Œæ ¹æ®ä½¿ç”¨çš„ [member omni_attenuation],有效照明区域å¯èƒ½" +"看起æ¥æ›´å°ã€‚æ— è®ºä½¿ç”¨ [member omni_attenuation] 为何值,光都ä¸ä¼šåˆ°è¾¾æ¤èŒƒå›´ä¹‹å¤–" +"的任何东西。\n" +"[b]注æ„:[/b][member omni_range] ä¸å— [member Spatial.scale] çš„å½±å“ï¼ˆæ— è®ºæ˜¯è¯¥" +"ç¯å…‰çš„缩放还是其父节点的缩放)。" #: doc/classes/OmniLight.xml msgid "See [enum ShadowDetail]." @@ -51297,7 +51335,6 @@ msgid "Returns the audio driver name for the given index." msgstr "返回给定索引的音频驱动程åºå称。" #: doc/classes/OS.xml -#, fuzzy msgid "" "Returns the [i]global[/i] cache data directory according to the operating " "system's standards. On Linux, this path can be overridden by setting the " @@ -51308,7 +51345,7 @@ msgid "" "Not to be confused with [method get_user_data_dir], which returns the " "[i]project-specific[/i] user data path." msgstr "" -"æ ¹æ®æ“ä½œç³»ç»Ÿçš„æ ‡å‡†è¿”å›ž[i]全局[/i]缓å˜æ•°æ®ç›®å½•ã€‚在桌é¢å¹³å°ä¸Šï¼Œå¯ä»¥é€šè¿‡åœ¨å¯åŠ¨é¡¹" +"æ ¹æ®æ“ä½œç³»ç»Ÿçš„æ ‡å‡†è¿”å›ž[i]全局[/i]缓å˜æ•°æ®ç›®å½•ã€‚在 Linux 上,å¯ä»¥é€šè¿‡åœ¨å¯åŠ¨é¡¹" "目之å‰è®¾ç½® [code]XDG_CACHE_HOME[/code] 环境å˜é‡æ¥è¦†ç›–æ¤è·¯å¾„。有关更多信æ¯ï¼Œè¯·" "å‚阅文档ä¸çš„ [url=$DOCS_URL/tutorials/io/data_paths.html]《Godot 项目ä¸çš„文件" "路径》[/url]。å¦è¯·å‚阅 [method get_config_dir] å’Œ [method get_data_dir]。\n" @@ -51362,7 +51399,6 @@ msgstr "" "[/codeblock]" #: doc/classes/OS.xml -#, fuzzy msgid "" "Returns the [i]global[/i] user configuration directory according to the " "operating system's standards. On Linux, this path can be overridden by " @@ -51373,7 +51409,7 @@ msgid "" "Not to be confused with [method get_user_data_dir], which returns the " "[i]project-specific[/i] user data path." msgstr "" -"æ ¹æ®æ“ä½œç³»ç»Ÿçš„æ ‡å‡†ï¼Œè¿”å›ž[i]全局[/i]用户é…置目录。在桌é¢å¹³å°ä¸Šï¼Œè¿™ä¸ªè·¯å¾„å¯ä»¥åœ¨" +"æ ¹æ®æ“ä½œç³»ç»Ÿçš„æ ‡å‡†ï¼Œè¿”å›ž[i]全局[/i]用户é…置目录。在 Linux 上,这个路径å¯ä»¥åœ¨" "å¯åŠ¨é¡¹ç›®å‰é€šè¿‡è®¾ç½®[code]XDG_CONFIG_HOME[/code]环境å˜é‡æ¥è¦†ç›–。更多信æ¯è¯·å‚è§" "文档ä¸[url=$DOCS_URL/tutorials/io/data_paths.html]《Godot 项目ä¸çš„文件路径》" "[/url]。å¦è¯·å‚阅 [method get_cache_dir] å’Œ [method get_data_dir]。\n" @@ -51398,7 +51434,6 @@ msgid "" msgstr "返回当å‰ä½¿ç”¨çš„视频驱动程åºï¼Œä½¿ç”¨[enum VideoDriver]ä¸çš„一个值。" #: doc/classes/OS.xml -#, fuzzy msgid "" "Returns the [i]global[/i] user data directory according to the operating " "system's standards. On Linux, this path can be overridden by setting the " @@ -51409,7 +51444,7 @@ msgid "" "Not to be confused with [method get_user_data_dir], which returns the " "[i]project-specific[/i] user data path." msgstr "" -"æ ¹æ®æ“ä½œç³»ç»Ÿçš„æ ‡å‡†ï¼Œè¿”å›ž[i]全局[/i]用户数æ®ç›®å½•ã€‚在桌é¢å¹³å°ä¸Šï¼Œè¿™ä¸ªè·¯å¾„å¯ä»¥åœ¨" +"æ ¹æ®æ“ä½œç³»ç»Ÿçš„æ ‡å‡†ï¼Œè¿”å›ž[i]全局[/i]用户数æ®ç›®å½•ã€‚在 Linux 上,这个路径å¯ä»¥åœ¨" "å¯åŠ¨é¡¹ç›®å‰é€šè¿‡è®¾ç½®[code]XDG_DATA_HOME[/code]环境å˜é‡æ¥è¦†ç›–。更多信æ¯è¯·å‚è§æ–‡" "æ¡£ä¸[url=$DOCS_URL/tutorials/io/data_paths.html]《Godot 项目ä¸çš„文件路径》[/" "url]。å¦è¯·å‚阅 [method get_cache_dir] å’Œ [method get_config_dir]。\n" @@ -53698,14 +53733,14 @@ msgstr "" "使用 [code]process_material[/code] å±žæ€§æ·»åŠ [ParticlesMaterial] æ¥é…置粒å外" "观和行为。或者,您å¯ä»¥æ·»åŠ 一个将应用于所有粒åçš„ [ShaderMaterial]。\n" "[b]注æ„:[/b][Particles] 仅在使用 GLES3 渲染器时有效。如果使用 GLES2 渲染器," -"请改用 [CPUParticles]。您å¯ä»¥é€šè¿‡é€‰æ‹©èŠ‚点,å•å‡» 3D 编辑器视窗顶部的" +"请改用 [CPUParticles]。您å¯ä»¥é€šè¿‡é€‰æ‹©èŠ‚点,å•å‡» 3D 编辑器视å£é¡¶éƒ¨çš„" "[b]Particles[/b]èœå•ï¼Œç„¶åŽé€‰æ‹©[b]转æ¢ä¸º CPUParticles[/b],将 [Particles] 转æ¢" "为 [CPUParticles]。\n" "[b]注æ„:[/b]在 macOS 上,渲染 [Particles] 比 [CPUParticles] è¦æ…¢ä¸Šå¾ˆå¤šï¼Œå› 为" "å˜æ¢å馈是在 CPU 上实现的,而ä¸æ˜¯ GPU。以 macOS ä¸ºç›®æ ‡æ—¶ï¼Œè¯·è€ƒè™‘ä½¿ç”¨ " "[CPUParticles]。\n" "[b]注æ„:[/b]在处ç†ç²’å节点åŽï¼Œè®°å¾—通过选择它æ¥æ›´æ–°å…¶ [member " -"visibility_aabb],å•å‡» 3D 编辑器视窗顶部的[b]Particles[/b]èœå•ï¼Œç„¶åŽé€‰æ‹©[b]生" +"visibility_aabb],å•å‡» 3D 编辑器视å£é¡¶éƒ¨çš„[b]Particles[/b]èœå•ï¼Œç„¶åŽé€‰æ‹©[b]生" "æˆå¯è§ AABB[/b]。å¦åˆ™ï¼Œç²’åå¯èƒ½ä¼šç”±äºŽç›¸æœºä½ç½®å’Œè§’度的改å˜çªç„¶æ¶ˆå¤±ã€‚" #: doc/classes/Particles.xml @@ -53860,15 +53895,14 @@ msgid "Particle systems (2D)" msgstr "ç²’å系统(2D)" #: doc/classes/Particles2D.xml -#, fuzzy msgid "2D Particles Demo" -msgstr "2D å¹³å°è·³è·ƒæ¼”示" +msgstr "2D ç²’å演示" #: doc/classes/Particles2D.xml msgid "" "2D Dodge The Creeps Demo (uses GPUParticles2D for the trail behind the " "player)" -msgstr "" +msgstr "2D Dodge The Creeps 演示(玩家身åŽçš„拖尾使用的是 GPUParticles2D)" #: doc/classes/Particles2D.xml msgid "Returns a rectangle containing the positions of all existing particles." @@ -58119,7 +58153,7 @@ msgid "" msgstr "" "Popup 是基本的 [Control],用于显示对è¯æ¡†å’Œå¼¹å‡ºçª—å£ã€‚默认情况下,它是一个å窗" "å£å’Œæ¨¡æ€ï¼Œå‚阅 [Control],并具有自定义弹出行为的辅助程åºã€‚所有弹出方法都确ä¿" -"在视窗ä¸æ£ç¡®æ”¾ç½®ã€‚" +"在视å£ä¸æ£ç¡®æ”¾ç½®ã€‚" #: doc/classes/Popup.xml msgid "Popup (show the control in modal form)." @@ -60422,7 +60456,7 @@ msgid "" "default window size. Stretch mode settings also use this as a reference when " "enabled." msgstr "" -"设置游æˆçš„主视窗高度。在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®" +"设置游æˆçš„主视å£é«˜åº¦ã€‚在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®" "时,也使用æ¤å‚数作为å‚考。" #: doc/classes/ProjectSettings.xml @@ -60451,7 +60485,7 @@ msgid "" "default window size. Stretch mode settings also use this as a reference when " "enabled." msgstr "" -"设置游æˆçš„主视窗宽度。在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®" +"设置游æˆçš„主视å£å®½åº¦ã€‚在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®" "时,也使用æ¤å‚数作为å‚考。" #: doc/classes/ProjectSettings.xml @@ -60585,7 +60619,7 @@ msgid "" "and is the recommended setting." msgstr "" "如果已å¯ç”¨ï¼Œåˆ™ä¼šåœ¨å°† [member Viewport.gui_disable_input] 设为 [code]false[/" -"code] ç¦ç”¨è§†åŒºçš„ GUI 输入时,将当å‰çš„é¼ æ ‡æ‚¬åœåŠèšç„¦ä¸¢å¼ƒã€‚\n" +"code] ç¦ç”¨è§†å£çš„ GUI 输入时,将当å‰çš„é¼ æ ‡æ‚¬åœåŠèšç„¦ä¸¢å¼ƒã€‚\n" "è¿™æ ·çš„è¡Œä¸ºèƒ½å¤Ÿå¸®åŠ©ä¿æŒ GUI 状æ€çš„å¥å£®ï¼Œè¾“å…¥æ¢å¤æ—¶ï¼Œæ— 论当时å‘生了什么都ä¸ä¼šäº§" "生æ„外的结果。\n" "如果已ç¦ç”¨ï¼Œä¼šä½¿ç”¨æ—§æœ‰è¡Œä¸ºï¼Œé™¤äº†ç¦ç”¨ GUI 输入本身ä¸ä¼šè¿›è¡Œé¢å¤–æ“作。\n" @@ -60596,8 +60630,8 @@ msgid "" "If [code]true[/code], swaps OK and Cancel buttons in dialogs on Windows and " "UWP to follow interface conventions." msgstr "" -"如果为 [code]true[/code],在Windowså’ŒUWP的对è¯æ¡†ä¸äº¤æ¢ç¡®å®šå’Œå–消按钮,以éµå¾ª" -"ç•Œé¢æƒ¯ä¾‹ã€‚" +"如果为 [code]true[/code],在 Windows å’Œ UWP 的对è¯æ¡†ä¸äº¤æ¢ç¡®å®šå’Œå–消按钮,以" +"éµå¾ªç•Œé¢æƒ¯ä¾‹ã€‚" #: doc/classes/ProjectSettings.xml msgid "" @@ -60639,9 +60673,9 @@ msgid "" "necessary for the internal logic of several [Control]s. The events assigned " "to the action can however be modified." msgstr "" -"默认用于确认焦点按钮ã€èœå•æˆ–列表项,或验è¯è¾“入的[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"默认用于确认焦点按钮ã€èœå•æˆ–列表项,或验è¯è¾“入的 [InputEventAction]。\n" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60650,9 +60684,9 @@ msgid "" "necessary for the internal logic of several [Control]s. The events assigned " "to the action can however be modified." msgstr "" -"默认放弃一个模æ€æˆ–挂起的输入的[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"默认用于放弃模æ€æˆ–挂起的输入的 [InputEventAction]。\n" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60661,9 +60695,9 @@ msgid "" "necessary for the internal logic of several [Control]s. The events assigned " "to the action can however be modified." msgstr "" -"默认在UIä¸å‘下移动的[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"默认在 UI ä¸å‘下移动的 [InputEventAction]。\n" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60676,8 +60710,8 @@ msgid "" msgstr "" "默认[InputEventAction]去[Control]的结æŸä½ç½®(例如[ItemList]或[Tree]ä¸çš„最åŽä¸€" "项),匹é…典型桌é¢UI系统ä¸[constant KEY_END]的行为。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60689,8 +60723,8 @@ msgid "" msgstr "" "默认èšç„¦åœºæ™¯ä¸çš„下一个[Control]çš„[InputEventAction]。焦点行为å¯ä»¥é€šè¿‡[member " "Control.focus_next]é…置。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60702,8 +60736,8 @@ msgid "" msgstr "" "默认èšç„¦åœºæ™¯ä¸çš„å‰ä¸€ä¸ª[Control]çš„[InputEventAction]。焦点行为å¯ä»¥é€šè¿‡[member " "Control.focus_previous]é…置。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60716,8 +60750,8 @@ msgid "" msgstr "" "默认的将进入[Control]的起始ä½ç½®ï¼ˆä¾‹å¦‚[ItemList]或[Tree]ä¸çš„第一个项目)时的" "[InputEventAction],与典型的桌é¢UI系统ä¸[constant KEY_HOME]的行为相匹é…。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬å¯¹äºŽå‡ ä¸ª[Control]" -"的内部逻辑是必è¦çš„。然而,分é…给动作的事件å¯ä»¥è¢«ä¿®æ”¹ã€‚" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª " +"[Control] 的内部逻辑所必需的。然而,分é…给动作的事件å¯ä»¥è¢«ä¿®æ”¹ã€‚" #: doc/classes/ProjectSettings.xml msgid "" @@ -60726,9 +60760,9 @@ msgid "" "necessary for the internal logic of several [Control]s. The events assigned " "to the action can however be modified." msgstr "" -"默认在UIä¸å‘左移动的[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"默认在 UI ä¸å‘左移动的[InputEventAction]。\n" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60742,8 +60776,8 @@ msgstr "" "默认的在 [Control](例如 [ItemList] 或 [Tree])ä¸å‘下翻页的 " "[InputEventAction]ï¼Œä¸Žå…¸åž‹æ¡Œé¢ UI ç³»ç»Ÿä¸ [constant KEY_PAGEDOWN] 的行为相匹" "é…。\n" -"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª " -"[Control] 的内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60757,8 +60791,8 @@ msgstr "" "默认的在 [Control](例如 [ItemList] 或 [Tree])ä¸å‘上翻页的 " "[InputEventAction]ï¼Œä¸Žå…¸åž‹æ¡Œé¢ UI ç³»ç»Ÿä¸ [constant KEY_PAGEUP] 的行为相匹" "é…。\n" -"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª " -"[Control] 的内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60767,9 +60801,9 @@ msgid "" "necessary for the internal logic of several [Control]s. The events assigned " "to the action can however be modified." msgstr "" -"默认在UIä¸å³ç§»çš„[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"默认在 UI ä¸å³ç§»çš„[InputEventAction]。\n" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60780,8 +60814,8 @@ msgid "" "to the action can however be modified." msgstr "" "默认选择[Control](例如[ItemList]或[Tree])ä¸çš„一个项目[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -60790,9 +60824,9 @@ msgid "" "necessary for the internal logic of several [Control]s. The events assigned " "to the action can however be modified." msgstr "" -"默认在UIä¸å‘上移动[InputEventAction]。\n" -"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„" -"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。" +"默认在 UI ä¸å‘上移动[InputEventAction]。\n" +"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需" +"çš„ï¼Œæ— æ³•åˆ é™¤ã€‚ä½†æ˜¯å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。" #: doc/classes/ProjectSettings.xml msgid "" @@ -63204,7 +63238,6 @@ msgstr "" "的值通常会给出最好的结果。å¦è§ [member rendering/quality/filters/use_fxaa]。" #: doc/classes/ProjectSettings.xml -#, fuzzy msgid "" "If [code]true[/code], uses a fast post-processing filter to make banding " "significantly less visible in 3D. 2D rendering is [i]not[/i] affected by " @@ -63224,13 +63257,18 @@ msgid "" "debanding at run-time, set [member Viewport.debanding] on the root " "[Viewport] instead." msgstr "" -"如果为 [code]true[/code],则使用快速åŽå¤„ç†è¿‡æ»¤å™¨ä½¿æ¡å¸¦æ˜Žæ˜¾ä¸é‚£ä¹ˆæ˜Žæ˜¾ã€‚在æŸäº›" -"情况下,去带å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动模å¼ã€‚建议仅在实际需è¦æ—¶å¯ç”¨åŽ»æ¡å¸¦ï¼Œå› 为" -"抖动模å¼ä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾æ›´å¤§ã€‚\n" +"如果为 [code]true[/code],则使用一个快速的åŽæœŸå¤„ç†æ»¤æ³¢å™¨ï¼Œä½¿ 3D 的带状现象明" +"显å‡å°‘。2D 渲染[i]ä¸å—[/i]去æ¡å¸¦çš„å½±å“ï¼Œé™¤éž [member Environment." +"background_mode] 为 [constant Environment.BG_CANVAS]。æ¤æ—¶ [member rendering/" +"quality/intended_usage/framebuffer_allocation] 也必须设为 [b]3D[/b]。\n" +"在æŸäº›æƒ…况下,去带å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动模å¼ã€‚建议仅在实际需è¦æ—¶å¯ç”¨åŽ»æ¡" +"å¸¦ï¼Œå› ä¸ºæŠ–åŠ¨æ¨¡å¼ä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾æ›´å¤§ã€‚\n" "[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚[member rendering/quality/depth/hdr] 也必须" "为 [code]true[/code] æ‰èƒ½ä½¿åŽ»è‰²å¸¦æœ‰æ•ˆã€‚\n" "[b]注æ„:[/b]已知在移动平å°ä¸Šçš„去色带å˜åœ¨ç ´åæ¸²æŸ“çš„é—®é¢˜ã€‚å› æ¤ï¼Œå»ºè®®åœ¨ç”¨äºŽç§»åŠ¨" -"å¹³å°æ—¶ç¦ç”¨æ¤é€‰é¡¹ã€‚" +"å¹³å°æ—¶ç¦ç”¨æ¤é€‰é¡¹ã€‚\n" +"[b]注æ„:[/b]这个属性在项目å¯åŠ¨æ—¶æ˜¯åªè¯»çš„。è¦åœ¨è¿è¡Œæ—¶è®¾ç½®åŽ»æ¡å¸¦ï¼Œè¯·åœ¨æ ¹ " +"[Viewport] 上设置 [member Viewport.debanding]。" #: doc/classes/ProjectSettings.xml msgid "" @@ -65372,6 +65410,13 @@ msgid "" "[code]offset[/code], and the character before [code]offset[/code] will be " "checked for the word boundary [code]\\b[/code]." msgstr "" +"在文本ä¸æœç´¢ç¼–译åŽçš„模å¼ã€‚如果找到,则将首个匹é…结果放在 [RegExMatch] 容器ä¸" +"返回,å¦åˆ™è¿”回 [code]null[/code]。\n" +"æœç´¢çš„范围å¯ä»¥ç”¨ [code]offset[/code] å’Œ [code]end[/code] 指定。å¯ç”¨äºŽåœ¨ä¸Šä¸€æ¬¡" +"æˆåŠŸæ‰¾åˆ°åŽå†æ¬¡ä½¿ç”¨ç›¸åŒçš„ [code]subject[/code] 调用这个方法,继ç»å¯»æ‰¾åŒ¹é…。设" +"置这些å‚æ•°å’Œä¼ å…¥ç¼©çŸåŽçš„å—符串是ä¸åŒçš„。例如,起点 [code]^[/code] ä¸ä¼šå— " +"[code]offset[/code] å½±å“,å•è¯è¾¹ç•Œ [code]\\b[/code] 会检查 [code]offset[/" +"code] 之å‰çš„å—符。" #: modules/regex/doc_classes/RegEx.xml msgid "" @@ -65386,9 +65431,15 @@ msgid "" "[code]offset[/code], and the character before [code]offset[/code] will be " "checked for the word boundary [code]\\b[/code]." msgstr "" +"在文本ä¸æœç´¢ç¼–译åŽçš„模å¼ã€‚返回 [RegExMatch] 容器的数组,其ä¸åŒ…å«çš„是互ä¸é‡å " +"的匹é…结果。如果没有找到匹é…,则返回空数组。\n" +"æœç´¢çš„范围å¯ä»¥ç”¨ [code]offset[/code] å’Œ [code]end[/code] 指定。å¯ç”¨äºŽåœ¨ä¸Šä¸€æ¬¡" +"æˆåŠŸæ‰¾åˆ°åŽå†æ¬¡ä½¿ç”¨ç›¸åŒçš„ [code]subject[/code] 调用这个方法,继ç»å¯»æ‰¾åŒ¹é…。设" +"置这些å‚æ•°å’Œä¼ å…¥ç¼©çŸåŽçš„å—符串是ä¸åŒçš„。例如,起点 [code]^[/code] ä¸ä¼šå— " +"[code]offset[/code] å½±å“,å•è¯è¾¹ç•Œ [code]\\b[/code] 会检查 [code]offset[/" +"code] 之å‰çš„å—符。" #: modules/regex/doc_classes/RegEx.xml -#, fuzzy msgid "" "Searches the text for the compiled pattern and replaces it with the " "specified string. Escapes and backreferences such as [code]$1[/code] and " @@ -65403,10 +65454,14 @@ msgid "" "[code]offset[/code], and the character before [code]offset[/code] will be " "checked for the word boundary [code]\\b[/code]." msgstr "" -"æœç´¢æ–‡æœ¬ä¸çš„编译模å¼ï¼Œå¹¶å°†å…¶æ›¿æ¢ä¸ºæŒ‡å®šçš„å—符串。诸如 [code]$1[/code] å’Œ " +"在文本ä¸æœç´¢ç¼–译åŽçš„模å¼ï¼Œå¹¶å°†å…¶æ›¿æ¢ä¸ºæŒ‡å®šçš„å—符串。诸如 [code]$1[/code] å’Œ " "[code]$name[/code] ç‰è½¬ä¹‰å’Œåå‘引用会被展开和解决。默认情况下,åªæœ‰ç¬¬ä¸€ä¸ªå®žä¾‹" -"被替æ¢ï¼Œä½†å¯ä»¥å¯¹æ‰€æœ‰å®žä¾‹è¿›è¡Œä¿®æ”¹ï¼ˆå…¨å±€æ›¿æ¢ï¼‰ã€‚å¯ä»¥æŒ‡å®šè¦æœç´¢çš„区域,而ä¸éœ€è¦" -"修改开始和结æŸé”šçš„ä½ç½®ã€‚" +"被替æ¢ï¼Œä½†å¯ä»¥å¯¹æ‰€æœ‰å®žä¾‹è¿›è¡Œä¿®æ”¹ï¼ˆå…¨å±€æ›¿æ¢ï¼‰ã€‚\n" +"æœç´¢çš„范围å¯ä»¥ç”¨ [code]offset[/code] å’Œ [code]end[/code] 指定。å¯ç”¨äºŽåœ¨ä¸Šä¸€æ¬¡" +"æˆåŠŸæ‰¾åˆ°åŽå†æ¬¡ä½¿ç”¨ç›¸åŒçš„ [code]subject[/code] 调用这个方法,继ç»å¯»æ‰¾åŒ¹é…。设" +"置这些å‚æ•°å’Œä¼ å…¥ç¼©çŸåŽçš„å—符串是ä¸åŒçš„。例如,起点 [code]^[/code] ä¸ä¼šå— " +"[code]offset[/code] å½±å“,å•è¯è¾¹ç•Œ [code]\\b[/code] 会检查 [code]offset[/" +"code] 之å‰çš„å—符。" #: modules/regex/doc_classes/RegExMatch.xml msgid "Contains the results of a [RegEx] search." @@ -65687,7 +65742,7 @@ msgstr "" "时,这个方法会被调用。它的行为å¯ä»¥é€šè¿‡è¦†ç›–脚本ä¸çš„ [method " "_setup_local_to_scene] 进行定制。\n" "对于大多数资æºï¼Œè¯¥æ–¹æ³•ä¸æ‰§è¡Œä»»ä½•åŸºæœ¬é€»è¾‘。[ViewportTexture] 执行自定义逻辑以" -"æ£ç¡®è®¾ç½®æœ¬åœ°è§†çª—ä¸çš„代ç†çº¹ç†å’Œæ ‡å¿—。" +"æ£ç¡®è®¾ç½®æœ¬åœ°è§†å£ä¸çš„代ç†çº¹ç†å’Œæ ‡å¿—。" #: doc/classes/Resource.xml msgid "" @@ -68854,12 +68909,11 @@ msgid "" "quality/dynamic_fonts/use_oversampling[/code] in [ProjectSettings]. The " "property can however be overridden at runtime as needed." msgstr "" -"为 [code]true[/code] æ—¶å¯ç”¨å—ä½“è¿‡é‡‡æ ·ã€‚è¿™æ„味ç€æ ¹æ®è§†çª—的缩放比例ä¸åŒï¼Œ" -"[DynamicFont] 渲染的大å°ä¼šæ¯”é…置大å°æ›´é«˜æˆ–更低。例如,如果视窗的缩放系数为 " -"1.5,那么é…置为 14 å·å¤§å°çš„å—体将会按照 21 å·å¤§å°æ¸²æŸ“([code]14 * 1.5[/" -"code])。\n" -"[b]注æ„:[/b]å—ä½“è¿‡é‡‡æ ·ä»…åœ¨è§†çª—æ‹‰ä¼¸æ¨¡å¼ä¸º [constant STRETCH_MODE_VIEWPORT] 且" -"拉伸比例模å¼ä¸æ˜¯ [constant STRETCH_ASPECT_IGNORE] 时有效。\n" +"为 [code]true[/code] æ—¶å¯ç”¨å—ä½“è¿‡é‡‡æ ·ã€‚è¿™æ„味ç€æ ¹æ®è§†å£çš„缩放比例ä¸åŒï¼Œ" +"[DynamicFont] 渲染的大å°ä¼šæ¯”é…置大å°æ›´é«˜æˆ–更低。例如,视å£çš„缩放系数为 1.5 " +"时,é…置大å°ä¸º 14 çš„å—体将会当作大å°ä¸º 21 渲染([code]14 * 1.5[/code])。\n" +"[b]注æ„:[/b]åªæœ‰åœ¨è§†å£æ‹‰ä¼¸æ¨¡å¼ä¸º [constant STRETCH_MODE_VIEWPORT] 且拉伸比例" +"模å¼ä¸æ˜¯ [constant STRETCH_ASPECT_IGNORE] 时,æ‰ä¼šä½¿ç”¨å—ä½“è¿‡é‡‡æ ·ã€‚\n" "[b]注æ„:[/b]项目å¯åŠ¨æ—¶ä¼šä¸ºæ´»åŠ¨çš„ [SceneTree] 自动设置该属性,å–值为 " "[ProjectSettings] çš„ [code]rendering/quality/dynamic_fonts/use_oversampling[/" "code]。ä¸è¿‡è¿è¡Œæ—¶å¯ä»¥æ ¹æ®éœ€è¦å¯¹è¯¥å±žæ€§è¿›è¡Œè¦†ç›–。" @@ -68932,7 +68986,7 @@ msgstr "当节点的é…置更改时å‘出。仅在 [code]tool[/code] 模å¼ä¸‹å #: doc/classes/SceneTree.xml msgid "Emitted whenever a node is removed from the [SceneTree]." -msgstr "当从 [SceneTree] ä¸åˆ 除节点时å‘出。" +msgstr "当从 [SceneTree] ä¸ç§»é™¤èŠ‚点时å‘出。" #: doc/classes/SceneTree.xml msgid "Emitted whenever a node is renamed." @@ -68968,15 +69022,15 @@ msgstr "当 [SceneTree] 层次结构å‘生å˜åŒ–(移动或é‡å‘½åå项ç‰ï¼ #: doc/classes/SceneTree.xml msgid "Call a group with no flags (default)." -msgstr "对组进行调用时,ä¸ä½¿ç”¨æ ‡å¿—(默认)。" +msgstr "对分组进行调用时,ä¸ä½¿ç”¨æ ‡å¿—(默认)。" #: doc/classes/SceneTree.xml msgid "Call a group in reverse scene order." -msgstr "对组进行调用时,使用逆场景åºã€‚" +msgstr "对分组进行调用时,使用逆场景åºã€‚" #: doc/classes/SceneTree.xml msgid "Call a group immediately (calls are normally made on idle)." -msgstr "对组进行调用时,立å³æ‰§è¡Œï¼ˆæ£å¸¸æƒ…况下是在空闲时调用的)。" +msgstr "对分组进行调用时,立å³æ‰§è¡Œï¼ˆæ£å¸¸æƒ…况下是在空闲时调用的)。" #: doc/classes/SceneTree.xml msgid "" @@ -68985,6 +69039,9 @@ msgid "" "call is unique or not. Therefore when the same method is called with " "different arguments, only the first call will be performed." msgstr "" +"å³ä¾¿æ‰§è¡Œäº†å¤šæ¬¡è°ƒç”¨ï¼Œä¹Ÿåªå¯¹åˆ†ç»„进行一次调用。\n" +"[b]注æ„:[/b]确定调用是å¦å”¯ä¸€æ—¶ä¸è€ƒè™‘å‚æ•°ã€‚å› æ¤ï¼Œå¦‚果使用ä¸åŒçš„å‚数调用了åŒä¸€" +"个方法,那么åªä¼šæ‰§è¡Œç¬¬ä¸€ä¸ªè°ƒç”¨ã€‚" #: doc/classes/SceneTree.xml msgid "No stretching." @@ -71377,10 +71434,10 @@ msgstr "" msgid "" "Rotation part of the local transformation in degrees, specified in terms of " "YXZ-Euler angles in the format (X angle, Y angle, Z angle)." -msgstr "旋转部分局部å˜æ¢ä¸ºåº¦ï¼ŒæŒ‰ YXZ-Euler è§’æ ¼å¼æŒ‡å®šï¼ˆX 角ã€Y 角ã€Z 角)。" +msgstr "" +"局部å˜æ¢çš„旋转部分,å•ä½ä¸ºåº¦ï¼Œä»¥ YXZ 欧拉角的形å¼è¡¨ç¤ºï¼ˆX 角ã€Y 角ã€Z 角)。" #: doc/classes/Spatial.xml -#, fuzzy msgid "" "Scale part of the local transformation.\n" "[b]Note:[/b] Mixed negative scales in 3D are not decomposable from the " @@ -71392,7 +71449,9 @@ msgid "" msgstr "" "局部å˜æ¢çš„缩放部分。\n" "[b]注æ„:[/b]3D ä¸ï¼Œå˜æ¢çŸ©é˜µæ˜¯æ— 法分解出æ£è´Ÿæ··åˆçš„缩放的。由于 Godot ä¸ä½¿ç”¨å˜" -"æ¢çŸ©é˜µæ¥è¡¨ç¤ºç¼©æ”¾ï¼Œå¾—到的缩放值è¦ä¹ˆå…¨æ£ã€è¦ä¹ˆå…¨è´Ÿã€‚" +"æ¢çŸ©é˜µæ¥è¡¨ç¤ºç¼©æ”¾ï¼Œå¾—到的缩放值è¦ä¹ˆå…¨æ£ã€è¦ä¹ˆå…¨è´Ÿã€‚\n" +"[b]注æ„:[/b]并ä¸æ˜¯æ‰€æœ‰èŠ‚点的外观都会被 [member scale] 属性缩放。例如," +"[Light] 的外观就ä¸å— [member scale] å½±å“。" #: doc/classes/Spatial.xml msgid "Local space [Transform] of this node, with respect to the parent node." @@ -73038,6 +73097,9 @@ msgid "" "[b]Note:[/b] [member spot_angle] is not affected by [member Spatial.scale] " "(the light's scale or its parent's scale)." msgstr "" +"èšå…‰ç¯çš„角度,å•ä½ä¸ºåº¦ã€‚\n" +"[b]注æ„:[/b][member spot_angle] ä¸å— [member Spatial.scale] çš„å½±å“ï¼ˆæ— è®ºæ˜¯è¯¥" +"ç¯å…‰çš„缩放还是其父节点的缩放)。" #: doc/classes/SpotLight.xml msgid "The spotlight's angular attenuation curve." @@ -73048,7 +73110,6 @@ msgid "The spotlight's light energy attenuation curve." msgstr "èšå…‰ç¯çš„å…‰é‡è¡°å‡æ›²çº¿ã€‚" #: doc/classes/SpotLight.xml -#, fuzzy msgid "" "The maximal range that can be reached by the spotlight. Note that the " "effectively lit area may appear to be smaller depending on the [member " @@ -73058,8 +73119,10 @@ msgid "" "(the light's scale or its parent's scale)." msgstr "" "èšå…‰ç¯å¯ä»¥è¾¾åˆ°çš„最大范围。请注æ„ï¼Œæ ¹æ®ä½¿ç”¨çš„ [member spot_attenuation],有效" -"照明区域å¯èƒ½çœ‹èµ·æ¥æ›´å°ã€‚æ— è®ºä½¿ç”¨[member spot_attenuation],光都ä¸ä¼šåˆ°è¾¾æ¤èŒƒå›´" -"之外的任何东西。" +"照明区域å¯èƒ½çœ‹èµ·æ¥æ›´å°ã€‚æ— è®º [member spot_attenuation] 为何值,光都ä¸ä¼šåˆ°è¾¾æ¤" +"范围之外的任何东西。\n" +"[b]注æ„:[/b][member spot_angle] ä¸å— [member Spatial.scale] çš„å½±å“ï¼ˆæ— è®ºæ˜¯è¯¥" +"ç¯å…‰çš„缩放还是其父节点的缩放)。" #: doc/classes/SpringArm.xml msgid "A helper node, mostly used in 3rd person cameras." @@ -76689,7 +76752,7 @@ msgid "" "Centers the viewport on the line the editing cursor is at. This also resets " "the [member scroll_horizontal] value to [code]0[/code]." msgstr "" -"å°†è§†åŒºç½®äºŽç¼–è¾‘å…‰æ ‡æ‰€åœ¨çš„è¡Œä¸Šã€‚è¿™ä¹Ÿä¼šå°† [member scroll_horizontal] 值é‡ç½®ä¸º " +"将视å£ç½®äºŽç¼–è¾‘å…‰æ ‡æ‰€åœ¨çš„è¡Œä¸Šã€‚è¿™ä¹Ÿä¼šå°† [member scroll_horizontal] 值é‡ç½®ä¸º " "[code]0[/code]。" #: doc/classes/TextEdit.xml @@ -76723,7 +76786,7 @@ msgid "" "will center at the cursor position after the move occurs." msgstr "" "å°†å…‰æ ‡ç§»åŠ¨åˆ°æŒ‡å®šçš„ [code]column[/code] 索引处。\n" -"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†çª—" +"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†å£" "å°†ä»¥å…‰æ ‡ä½ç½®ä¸ºä¸å¿ƒã€‚" #: doc/classes/TextEdit.xml @@ -76735,7 +76798,7 @@ msgid "" "[code]line[/code] can be hidden using [method set_line_as_hidden]." msgstr "" "在指定的 [code]line[/code] ç´¢å¼•å¤„ç§»åŠ¨å…‰æ ‡ã€‚\n" -"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†çª—" +"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†å£" "å°†ä»¥å…‰æ ‡ä½ç½®ä¸ºä¸å¿ƒã€‚\n" "如果 [code]can_be_hidden[/code] 设置为 [code]true[/code],则å¯ä»¥ä½¿ç”¨ [method " "set_line_as_hidden] éšè—指定的 [code]line[/code]。" @@ -84329,16 +84392,16 @@ msgid "" "to be upside down. Enabling [member render_target_v_flip] will display the " "Viewport with the correct orientation." msgstr "" -"Viewport 会在å±å¹•ä¸Šåˆ›å»ºä¸åŒçš„视图,或者是å¦ä¸€ä¸ªè§†çª—ä¸çš„å视图。å代 2D 节点会" +"Viewport 会在å±å¹•ä¸Šåˆ›å»ºä¸åŒçš„视图,或者是å¦ä¸€ä¸ªè§†å£ä¸çš„å视图。å代 2D 节点会" "在其上显示,å代 3D æ‘„åƒæœºèŠ‚点也会在其上渲染。\n" -"å¦å¤–,视窗å¯ä»¥æœ‰è‡ªå·±çš„ 2D 或 3D 世界,所以它们ä¸ä¼šä¸Žå…¶ä»–视窗共享其所绘制的内" +"å¦å¤–,视å£å¯ä»¥æœ‰è‡ªå·±çš„ 2D 或 3D 世界,所以它们ä¸ä¼šä¸Žå…¶ä»–视å£å…±äº«å…¶æ‰€ç»˜åˆ¶çš„内" "容。\n" -"如果视窗是 [ViewportContainer] çš„å节点,它将自动å 用其大å°ï¼Œå¦åˆ™å¿…须手动设" +"如果视å£æ˜¯ [ViewportContainer] çš„å节点,它将自动å 用其大å°ï¼Œå¦åˆ™å¿…须手动设" "置。\n" -"视窗也å¯ä»¥é€‰æ‹©æˆä¸ºéŸ³é¢‘监å¬è€…ï¼Œä¼šæ ¹æ®å®ƒçš„ 2D 或 3D æ‘„åƒæœºçš„å节点æ¥äº§ç”Ÿä½ç½®éŸ³" +"视å£ä¹Ÿå¯ä»¥é€‰æ‹©æˆä¸ºéŸ³é¢‘监å¬è€…ï¼Œä¼šæ ¹æ®å®ƒçš„ 2D 或 3D æ‘„åƒæœºçš„å节点æ¥äº§ç”Ÿä½ç½®éŸ³" "频。\n" -"å¦å¤–,如果设备有多个å±å¹•ï¼Œè§†çª—å¯ä»¥è¢«åˆ†é…到ä¸åŒçš„å±å¹•ã€‚\n" -"最åŽï¼Œè§†çª—也å¯ä»¥ä½œä¸ºæ¸²æŸ“ç›®æ ‡ï¼Œåœ¨è¿™ç§æƒ…况下,除éžç›¸å…³çš„纹ç†è¢«ç”¨äºŽç»˜åˆ¶ï¼Œå¦åˆ™å®ƒ" +"å¦å¤–,如果设备有多个å±å¹•ï¼Œè§†å£å¯ä»¥è¢«åˆ†é…到ä¸åŒçš„å±å¹•ã€‚\n" +"最åŽï¼Œè§†å£ä¹Ÿå¯ä»¥ä½œä¸ºæ¸²æŸ“ç›®æ ‡ï¼Œåœ¨è¿™ç§æƒ…况下,除éžç›¸å…³çš„纹ç†è¢«ç”¨äºŽç»˜åˆ¶ï¼Œå¦åˆ™å®ƒ" "们将ä¸å¯è§ã€‚\n" "[b]注æ„:[/b]默认情况下,Godot 3.x ä¸æ–°åˆ›å»ºçš„ Viewport æ˜¯ä¸Šä¸‹é¢ å€’çš„ã€‚å¯ç”¨ " "[member render_target_v_flip] å¯ä»¥ä½¿è¯¥ Viewport 使用æ£ç¡®çš„æœå‘显示。" @@ -84385,7 +84448,7 @@ msgstr "返回激活的 3D 相机。" #: doc/classes/Viewport.xml msgid "Returns the total transform of the viewport." -msgstr "返回视窗的总的å˜æ¢ã€‚" +msgstr "返回视å£çš„总的å˜æ¢ã€‚" #: doc/classes/Viewport.xml msgid "Returns the topmost modal in the stack." @@ -84399,7 +84462,7 @@ msgstr "返回该 [Viewport] ä¸é¼ æ ‡çš„ä½ç½®ï¼Œä½¿ç”¨è¯¥ [Viewport] çš„åæ ‡ #: doc/classes/Viewport.xml msgid "Returns information about the viewport from the rendering pipeline." -msgstr "返回渲染管é“ä¸å…³äºŽè§†çª—çš„ä¿¡æ¯ã€‚" +msgstr "返回渲染管é“ä¸å…³äºŽè§†å£çš„ä¿¡æ¯ã€‚" #: doc/classes/Viewport.xml msgid "Returns the [enum ShadowAtlasQuadrantSubdiv] of the specified quadrant." @@ -84420,7 +84483,7 @@ msgid "" "img.flip_y()\n" "[/codeblock]" msgstr "" -"返回该视窗的纹ç†ã€‚\n" +"返回该视å£çš„纹ç†ã€‚\n" "[b]注æ„:[/b]由于 OpenGL 的工作方å¼ï¼Œäº§ç”Ÿçš„ [ViewportTexture] 是垂直翻转的。" "ä½ å¯ä»¥åœ¨ [method Texture.get_data] 的结果上使用 [method Image.flip_y] æ¥å°†å…¶" "翻转回去,例如:\n" @@ -84459,7 +84522,7 @@ msgid "" "Alternative to [constant Node.NOTIFICATION_DRAG_BEGIN] and [constant Node." "NOTIFICATION_DRAG_END] when you prefer polling the value." msgstr "" -"如果该视区目å‰æ£åœ¨æ‰§è¡Œæ‹–拽æ“作,则返回 [code]true[/code]。\n" +"如果该视å£ç›®å‰æ£åœ¨æ‰§è¡Œæ‹–拽æ“作,则返回 [code]true[/code]。\n" "å¦‚æžœä½ æ›´å€¾å‘于对其进行轮询,那么就å¯ä»¥ä½œä¸º [constant Node." "NOTIFICATION_DRAG_BEGIN] å’Œ [constant Node.NOTIFICATION_DRAG_END] 的替代å“。" @@ -84540,7 +84603,6 @@ msgstr "" "全局画布å˜æ¢ã€‚" #: doc/classes/Viewport.xml -#, fuzzy msgid "" "If [code]true[/code], uses a fast post-processing filter to make banding " "significantly less visible in 3D. 2D rendering is [i]not[/i] affected by " @@ -84555,9 +84617,13 @@ msgid "" "[b]Note:[/b] Only available on the GLES3 backend. [member hdr] must also be " "[code]true[/code] for debanding to be effective." msgstr "" -"如果为 [code]true[/code],则使用一个快速的åŽæœŸå¤„ç†æ»¤æ³¢å™¨ï¼Œä½¿å¸¦çŠ¶çŽ°è±¡æ˜Žæ˜¾å‡" -"少。在æŸäº›æƒ…况下,去带å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动模å¼ã€‚建议åªæœ‰åœ¨å®žé™…需è¦æ—¶æ‰å¯" -"ç”¨åŽ»å¸¦ï¼Œå› ä¸ºæŠ–åŠ¨æ¨¡å¼ä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾å˜å¤§ã€‚\n" +"如果为 [code]true[/code],则使用一个快速的åŽæœŸå¤„ç†æ»¤æ³¢å™¨ï¼Œä½¿ 3D 的带状现象明" +"显å‡å°‘。2D 渲染[i]ä¸å—[/i]去æ¡å¸¦çš„å½±å“ï¼Œé™¤éž [member Environment." +"background_mode] 为 [constant Environment.BG_CANVAS]。æ¤æ—¶ [member usage] 也" +"必须设为 [constant USAGE_3D]。å¦è¯·å‚阅 [member ProjectSettings.rendering/" +"quality/filters/use_debanding]。\n" +"在æŸäº›æƒ…况下,去æ¡å¸¦å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动图案。建议åªæœ‰åœ¨å®žé™…需è¦æ—¶æ‰å¯ç”¨" +"去æ¡å¸¦ï¼Œå› ä¸ºæŠ–åŠ¨å›¾æ¡ˆä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾å˜å¤§ã€‚\n" "[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚[member hdr] 也必须是 [code]true[/code] æ‰" "能使去色带生效。" @@ -84566,13 +84632,12 @@ msgid "The overlay mode for test rendered geometry in debug purposes." msgstr "åœ¨è°ƒè¯•æ—¶ï¼Œç”¨äºŽæµ‹è¯•æ¸²æŸ“çš„å‡ ä½•å›¾å½¢çš„å åŠ æ¨¡å¼ã€‚" #: doc/classes/Viewport.xml -#, fuzzy msgid "" "If [code]true[/code], the viewport will disable 3D rendering. To actually " "disable allocation of 3D buffers, set [member usage] instead." msgstr "" -"如果为 [code]true[/code],该视å£å°†ç¦ç”¨ 3D 渲染。对于实际ç¦ç”¨ï¼Œä½¿ç”¨ " -"[code]usage[/code]。" +"如果为 [code]true[/code],该视å£å°†ç¦ç”¨ 3D 渲染。è¦å®žé™…ç¦ç”¨ 3D 缓冲区的分é…," +"请设置 [member usage]。" #: doc/classes/Viewport.xml msgid "" @@ -84616,7 +84681,7 @@ msgid "" "[b]Note:[/b] Only available on the GLES3 backend." msgstr "" "如果为 [code]true[/code],视å£çš„渲染将获益于高动æ€èŒƒå›´ç®—法。高动æ€èŒƒå›´å…许视" -"窗接收 0-1 范围以外的数值。在 Godot ä¸ HDR 默认使用åŠç²¾åº¦æµ®ç‚¹æ•°ï¼ˆ16 ä½ï¼‰ã€‚è¦" +"å£æŽ¥æ”¶ 0-1 范围以外的数值。在 Godot ä¸ HDR 默认使用åŠç²¾åº¦æµ®ç‚¹æ•°ï¼ˆ16 ä½ï¼‰ã€‚è¦" "使用全精度浮点数(32 ä½ï¼‰ï¼Œè¯·å¯ç”¨ [member use_32_bpc_depth]。\n" "[b]注æ„:[/b]需è¦å°† [member usage] 设置为 [constant USAGE_3D] 或 [constant " "USAGE_3D_NO_EFFECTS]ï¼Œå› ä¸º HDR ä¸æ”¯æŒ 2D。\n" @@ -84635,7 +84700,7 @@ msgid "" "require input in linear color space!" msgstr "" "如果为 [code]true[/code],3D 渲染åŽçš„结果将ä¸ä¼šåº”用线性到 sRGB 的颜色转æ¢ã€‚当" -"视å£è¢«ç”¨ä½œæ¸²æŸ“ç›®æ ‡æ—¶ï¼Œè¿™ç‚¹å¾ˆé‡è¦ï¼Œå› 为渲染结果会被用作å¦ä¸€ä¸ªè§†çª—ä¸æ¸²æŸ“çš„ 3D " +"视å£è¢«ç”¨ä½œæ¸²æŸ“ç›®æ ‡æ—¶ï¼Œè¿™ç‚¹å¾ˆé‡è¦ï¼Œå› 为渲染结果会被用作å¦ä¸€ä¸ªè§†å£ä¸æ¸²æŸ“çš„ 3D " "物体的纹ç†ã€‚如果视å£è¢«ç”¨æ¥åˆ›å»ºä¸åŸºäºŽé¢œè‰²çš„æ•°æ®ï¼Œå™ªå£°ã€é«˜åº¦å›¾ã€é‡‡å›¾ç‰ï¼Œè¿™ä¹Ÿå¾ˆ" "é‡è¦ã€‚当视å£è¢«ç”¨ä½œ 2D 对象的纹ç†æ—¶ï¼Œæˆ–者视å£æ˜¯ä½ 的最终输出时,请ä¸è¦å¯ç”¨è¿™ä¸ª" "功能。对于 GLES2 驱动æ¥è¯´ï¼Œè¿™å°†æŠŠ sRGB 输出转æ¢ä¸ºçº¿æ€§è¾“出,这应该åªç”¨äºŽéœ€è¦çº¿" @@ -84725,7 +84790,7 @@ msgid "" msgstr "" "阴影图集的分辨率(用于全å‘光和èšå…‰ï¼‰ã€‚该值将四èˆäº”入到最接近的 2 的幂。\n" "[b]注æ„:[/b]如果设置为 [code]0[/code],点阴影和方å‘阴影[i]都[/i]å°†ä¸å¯è§ã€‚ç”±" -"于用户创建的视区默认值为 [code]0[/code]ï¼Œå› æ¤å¿…须手动将æ¤å€¼è®¾ç½®ä¸ºå¤§äºŽ " +"于用户创建的视å£é»˜è®¤å€¼ä¸º [code]0[/code]ï¼Œå› æ¤å¿…须手动将æ¤å€¼è®¾ç½®ä¸ºå¤§äºŽ " "[code]0[/code](一般至少是 [code]256[/code])。" #: doc/classes/Viewport.xml @@ -84736,7 +84801,7 @@ msgid "" "Values around [code]0.5[/code] generally give the best results. See also " "[member fxaa]." msgstr "" -"如果设置为大于 [code]0.0[/code] 的值,对比度适应性é”化将被应用到3D视窗ä¸ã€‚è¿™" +"如果设置为大于 [code]0.0[/code] 的值,对比度适应性é”化将被应用到3D视å£ä¸ã€‚è¿™" "具有较低的性能æˆæœ¬ï¼Œå¯ä»¥ç”¨æ¥æ¢å¤ä½¿ç”¨ FXAA 所æŸå¤±çš„一些é”度。一般æ¥è¯´ï¼Œ" "[code]0.5[/code] å·¦å³çš„数值å¯ä»¥å¾—到最好的效果。å¦è¯·å‚阅 [member fxaa]。" @@ -84759,7 +84824,6 @@ msgid "" msgstr "如果为 [code]true[/code],该视å£åº”使其背景渲染为é€æ˜Žã€‚" #: doc/classes/Viewport.xml -#, fuzzy msgid "" "The viewport's rendering mode. This controls which buffers are allocated for " "the viewport (2D only, or 2D + 3D). 2D-only options can reduce memory usage " @@ -84768,7 +84832,8 @@ msgid "" "USAGE_2D_NO_SAMPLING], [member hdr] will have no effect when enabled since " "HDR is not supported for 2D." msgstr "" -"视区的渲染模å¼ã€‚\n" +"该视å£çš„渲染模å¼ã€‚控制的是为该视å£åˆ†é…哪些缓冲区(仅 2D 或者 2D + 3D)。仅 " +"2D 的选项能够é™ä½Žå†…å˜å 用ã€ç•¥å¾®æå‡æ€§èƒ½ï¼Œå°¤å…¶æ˜¯åœ¨ä½Žç«¯è®¾å¤‡ä¸Šã€‚\n" "[b]注æ„:[/b]如果设为 [constant USAGE_2D] 或 [constant " "USAGE_2D_NO_SAMPLING],则å¯ç”¨ [member hdr] ä¸ä¼šç”Ÿæ•ˆï¼Œå› 为 2D ä¸æ”¯æŒ HDR。" @@ -84783,7 +84848,7 @@ msgid "" "enable [member debanding] instead.\n" "[b]Note:[/b] Only available on the GLES3 backend." msgstr "" -"如果为 [code]true[/code],分é…该视窗的帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ" +"如果为 [code]true[/code],分é…该视å£çš„帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ" "ä¸æ˜¯åŠæµ®ç‚¹æ•°ç²¾åº¦ï¼ˆ16 ä½ï¼‰ã€‚仅在åŒæ—¶å¯ç”¨ [member hdr] 时有效。\n" "[b]注æ„:[/b]å¯ç”¨è¿™ä¸ªè®¾ç½®ä¸ä¼šæå‡æ¸²æŸ“è´¨é‡ã€‚使用完整浮点数精度较慢,一般åªæœ‰è¦" "求更高精度的高级ç€è‰²å™¨éœ€è¦ä½¿ç”¨ã€‚如果是è¦å‡å°‘æ¡å¸¦æ•ˆåº”,请å¯ç”¨ [member " @@ -85015,7 +85080,7 @@ msgstr "" #: doc/classes/ViewportContainer.xml msgid "" "If [code]true[/code], the viewport will be scaled to the control's size." -msgstr "为 [code]true[/code] 时视窗将被缩放到控件的大å°ã€‚" +msgstr "为 [code]true[/code] 时视å£å°†è¢«ç¼©æ”¾åˆ°æŽ§ä»¶çš„大å°ã€‚" #: doc/classes/ViewportContainer.xml msgid "" @@ -85046,7 +85111,7 @@ msgid "" msgstr "" "å°† [Viewport] 节点的内容显示为一个动æ€çš„ [Texture]。å¯ä»¥ç”¨æ¥åœ¨åŒä¸€ä¸ªåœºæ™¯ä¸æ··" "åˆæŽ§ä»¶ã€2D å’Œ 3Då…ƒç´ ã€‚\n" -"è¦é€šè¿‡ä»£ç 创建 ViewportTextureï¼Œè¯·ä½¿ç”¨ç›®æ ‡è§†çª—ä¸Šçš„ [method Viewport." +"è¦é€šè¿‡ä»£ç 创建 ViewportTextureï¼Œè¯·ä½¿ç”¨ç›®æ ‡è§†å£ä¸Šçš„ [method Viewport." "get_texture] 方法。" #: doc/classes/ViewportTexture.xml @@ -85402,6 +85467,8 @@ msgid "" "value will make the [VisualInstance] reliably draw on top of other " "[VisualInstance]s that are otherwise positioned at the same spot." msgstr "" +"这个 [VisualInstance] 所使用的排åºå移é‡ã€‚调高åŽï¼Œè¯¥ [VisualInstance] 会稳定" +"地绘制在åŒä¸€ä½ç½®çš„其他 [VisualInstance] 之上。" #: doc/classes/VisualInstance.xml msgid "" @@ -85411,6 +85478,10 @@ msgid "" "The position based sorting instead allows to better control the drawing " "order when working with [Particles] and [CPUParticles]." msgstr "" +"如果为 [code]true[/code]ï¼Œåˆ™è¯¥å¯¹è±¡ä¼šæ ¹æ®å…¶ [AABB] ä¸å¿ƒç‚¹æŽ’åºã€‚å¦åˆ™ä¼šæ ¹æ®å…¶å…¨" +"å±€ä½ç½®æŽ’åºã€‚\n" +"对 3D æ¨¡åž‹è€Œè¨€ï¼Œæ ¹æ® [AABB] çš„ä¸å¿ƒç‚¹æŽ’åºä¸€èˆ¬æ›´ä¸ºç²¾ç¡®ã€‚使用 [Particles] å’Œ " +"[CPUParticles] æ—¶ï¼Œæ ¹æ®ä½ç½®æŽ’åºèƒ½å¤Ÿæ›´å¥½åœ°æŽ§åˆ¶ç»˜åˆ¶é¡ºåºã€‚" #: modules/visual_script/doc_classes/VisualScript.xml msgid "A script implemented in the Visual Script programming environment." @@ -87417,10 +87488,10 @@ msgstr "" "VisualServer 是完全ä¸é€æ˜Žçš„,它的内部结构的完全的具体实现ä¸èƒ½è¢«è®¿é—®ã€‚\n" "VisualServer å¯ä»¥ç”¨æ¥å®Œå…¨ç»•è¿‡åœºæ™¯ç³»ç»Ÿã€‚\n" "å¯ä½¿ç”¨ [code]*_create[/code] 函数创建资æºã€‚\n" -"所有的对象都被绘制到视窗ä¸ã€‚ä½ å¯ä»¥ä½¿ç”¨é™„在 [SceneTree] 上的 [Viewport],或者" +"所有的对象都被绘制到视å£ä¸ã€‚ä½ å¯ä»¥ä½¿ç”¨é™„在 [SceneTree] 上的 [Viewport],或者" "用 [method viewport_create] 自己创建一个。当使用自定义场景或画布时,需è¦ä½¿ç”¨ " "[method viewport_set_scenario] 或 [method viewport_attach_canvas] 将场景或画" -"å¸ƒé™„åŠ åˆ°è§†çª—ä¸Šã€‚\n" +"å¸ƒé™„åŠ åˆ°è§†å£ä¸Šã€‚\n" "在 3D ä¸ï¼Œæ‰€æœ‰çš„视觉对象都必须与一个场景相关è”。场景是世界的一个视觉表现。如" "果从一个æ£åœ¨è¿è¡Œçš„游æˆä¸è®¿é—®è§†è§‰æœåŠ¡ï¼Œåœºæ™¯å¯ä»¥é€šè¿‡ [method Spatial." "get_world] ä»Žåœºæ™¯æ ‘ä¸çš„任何 [Spatial] 节点访问。å¦å¤–,å¯ä»¥ç”¨ [method " @@ -87431,7 +87502,7 @@ msgstr "" "一个实例。实例也必须使用 [method instance_set_scenario] é™„åŠ åˆ°åœºæ™¯ä¸ï¼Œä»¥ä¾¿å¯" "è§ã€‚\n" "在 2D ä¸ï¼Œæ‰€æœ‰å¯è§å¯¹è±¡éƒ½æ˜¯æŸç§å½¢å¼çš„画布项目。为了å¯è§ï¼Œä¸€ä¸ªç”»å¸ƒé¡¹éœ€è¦æ˜¯è¿žæŽ¥" -"到视窗的画布的å项,或者它需è¦æ˜¯æœ€ç»ˆè¿žæŽ¥åˆ°ç”»å¸ƒçš„å¦ä¸€ä¸ªç”»å¸ƒé¡¹çš„å项。" +"到视å£çš„画布的å项,或者它需è¦æ˜¯æœ€ç»ˆè¿žæŽ¥åˆ°ç”»å¸ƒçš„å¦ä¸€ä¸ªç”»å¸ƒé¡¹çš„å项。" #: doc/classes/VisualServer.xml msgid "Sets images to be rendered in the window margin." @@ -87660,7 +87731,7 @@ msgid "" "Sets the parent for the [CanvasItem]. The parent can be another canvas item, " "or it can be the root canvas that is attached to the viewport." msgstr "" -"设置[CanvasItem]的父级。父级å¯ä»¥æ˜¯å¦ä¸€ä¸ªç”»å¸ƒé¡¹ç›®ï¼Œä¹Ÿå¯ä»¥æ˜¯è¿žæŽ¥åˆ°è§†çª—çš„æ ¹ç”»" +"设置[CanvasItem]的父级。父级å¯ä»¥æ˜¯å¦ä¸€ä¸ªç”»å¸ƒé¡¹ç›®ï¼Œä¹Ÿå¯ä»¥æ˜¯è¿žæŽ¥åˆ°è§†å£çš„æ ¹ç”»" "布。" #: doc/classes/VisualServer.xml @@ -89743,7 +89814,7 @@ msgid "" "[/codeblock]" msgstr "" "在两个纹ç†ä¹‹é—´åˆ›å»ºæ›´æ–°é“¾ï¼Œä¸Ž [ViewportTexture] 的原ç†ç±»ä¼¼ã€‚基础纹ç†ä¸º " -"[Viewport] 的纹ç†æ—¶ï¼Œè§†åŒºæ¯æ–°æ¸²æŸ“一帧,代ç†çº¹ç†å°±ä¼šè‡ªåŠ¨æ”¶åˆ°æ›´æ–°ã€‚\n" +"[Viewport] 的纹ç†æ—¶ï¼Œè§†å£æ¯æ–°æ¸²æŸ“一帧,代ç†çº¹ç†å°±ä¼šè‡ªåŠ¨æ”¶åˆ°æ›´æ–°ã€‚\n" "例如,æ¤å¤„的代ç 会利用 VisualServer API å°†ä¸€å¼ é€šç”¨çš„ [ImageTexture] 链接到 " "[Viewport] 的纹ç†è¾“出上:\n" "[codeblock]\n" @@ -89781,7 +89852,7 @@ msgstr "设置视图的相机。" #: doc/classes/VisualServer.xml msgid "Sets a viewport's canvas." -msgstr "设置视窗的画布。" +msgstr "设置视å£çš„画布。" #: doc/classes/VisualServer.xml msgid "" @@ -89804,18 +89875,18 @@ msgid "" "manually. For further optimization, see [method " "viewport_set_render_direct_to_screen]." msgstr "" -"将视窗å¤åˆ¶åˆ°å±å¹•ä¸Šç”± [code]rect[/code] 指定的区域。如果 [member Viewport." -"render_direct_to_screen] 为 [code]true[/code],那么视窗就ä¸ä¼šä½¿ç”¨å¸§ç¼“冲,视窗" -"的内容会直接渲染到å±å¹•ä¸Šã€‚然而,请注æ„ï¼Œæ ¹è§†çª—æ˜¯æœ€åŽç»˜åˆ¶çš„ï¼Œå› æ¤å®ƒå°†åœ¨å±å¹•ä¸Š" -"ç»˜åˆ¶ã€‚ç›¸åº”åœ°ï¼Œä½ å°±å¿…é¡»å°†æ ¹è§†çª—è®¾ç½®ä¸ºä¸€ä¸ªä¸è¦†ç›–ä½ æ‰€é™„åŠ çš„è¿™ä¸ªè§†çª—çš„åŒºåŸŸã€‚\n" -"ä¾‹å¦‚ï¼Œä½ å¯ä»¥ç”¨ä»¥ä¸‹ä»£ç å°†æ ¹è§†çª—è®¾ç½®ä¸ºå®Œå…¨ä¸æ¸²æŸ“。\n" +"将视å£å¤åˆ¶åˆ°å±å¹•ä¸Šç”± [code]rect[/code] 指定的区域。如果 [member Viewport." +"render_direct_to_screen] 为 [code]true[/code],那么视å£å°±ä¸ä¼šä½¿ç”¨å¸§ç¼“冲,视å£" +"的内容会直接渲染到å±å¹•ä¸Šã€‚然而,请注æ„ï¼Œæ ¹è§†å£æ˜¯æœ€åŽç»˜åˆ¶çš„ï¼Œå› æ¤å®ƒå°†åœ¨å±å¹•ä¸Š" +"ç»˜åˆ¶ã€‚ç›¸åº”åœ°ï¼Œä½ å°±å¿…é¡»å°†æ ¹è§†å£è®¾ç½®ä¸ºä¸€ä¸ªä¸è¦†ç›–ä½ æ‰€é™„åŠ çš„è¿™ä¸ªè§†å£çš„区域。\n" +"ä¾‹å¦‚ï¼Œä½ å¯ä»¥ç”¨ä»¥ä¸‹ä»£ç å°†æ ¹è§†å£è®¾ç½®ä¸ºå®Œå…¨ä¸æ¸²æŸ“。\n" "[codeblock]\n" "func _ready():\n" " get_viewport().set_attach_to_screen_rect(Rect2())\n" " $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n" "[/codeblock]\n" "使用这个方法å¯ä»¥å¸¦æ¥æ˜Žæ˜¾çš„优化,特别是在低端设备上。然而,它的代价是必须手动" -"管ç†ä½ 的视窗。进一æ¥çš„优化请å‚阅 [method " +"管ç†ä½ 的视å£ã€‚进一æ¥çš„优化请å‚阅 [method " "viewport_set_render_direct_to_screen]。" #: doc/classes/VisualServer.xml @@ -89826,32 +89897,32 @@ msgid "" "Once finished with your RID, you will want to free the RID using the " "VisualServer's [method free_rid] static method." msgstr "" -"åˆ›å»ºä¸€ä¸ªç©ºè§†çª—å¹¶å°†å…¶æ·»åŠ åˆ° VisualServer ä¸ã€‚å¯ä»¥ç”¨è¿”回的RIDæ¥è®¿é—®å®ƒã€‚这个RID" +"创建一个空视å£å¹¶å°†å…¶æ·»åŠ 到 VisualServer ä¸ã€‚å¯ä»¥ç”¨è¿”回的RIDæ¥è®¿é—®å®ƒã€‚这个RID" "将用于所有[code]viewport_*[/code] çš„VisualServer函数。\n" "ä¸€æ—¦ä½ ç”¨å®Œäº†RIDï¼Œä½ è¦ä½¿ç”¨VisualServerçš„[method free_rid]é™æ€æ–¹æ³•é‡Šæ”¾RID。" #: doc/classes/VisualServer.xml msgid "Detaches the viewport from the screen." -msgstr "将视窗从å±å¹•ä¸Šåˆ†ç¦»ã€‚" +msgstr "将视å£ä»Žå±å¹•ä¸Šåˆ†ç¦»ã€‚" #: doc/classes/VisualServer.xml msgid "" "Returns a viewport's render information. For options, see the [enum " "ViewportRenderInfo] constants." -msgstr "返回视窗的渲染信æ¯ã€‚有关选项,请å‚阅 [enum ViewportRenderInfo] 常é‡ã€‚" +msgstr "返回视å£çš„渲染信æ¯ã€‚有关选项,请å‚阅 [enum ViewportRenderInfo] 常é‡ã€‚" #: doc/classes/VisualServer.xml msgid "Returns the viewport's last rendered frame." -msgstr "返回视窗的最åŽæ¸²æŸ“帧。" +msgstr "返回视å£çš„最åŽæ¸²æŸ“帧。" #: doc/classes/VisualServer.xml msgid "Detaches a viewport from a canvas and vice versa." -msgstr "从画布分离视窗,å之亦然。" +msgstr "从画布分离视å£ï¼Œå之亦然。" #: doc/classes/VisualServer.xml msgid "If [code]true[/code], sets the viewport active, else sets it inactive." msgstr "" -"如果为 [code]true[/code],则将视窗设置为活动状æ€ï¼Œå¦åˆ™å°†å…¶è®¾ç½®ä¸ºéžæ´»åŠ¨çŠ¶æ€ã€‚" +"如果为 [code]true[/code],则将视å£è®¾ç½®ä¸ºæ´»åŠ¨çŠ¶æ€ï¼Œå¦åˆ™å°†å…¶è®¾ç½®ä¸ºéžæ´»åŠ¨çŠ¶æ€ã€‚" #: doc/classes/VisualServer.xml msgid "" @@ -89859,37 +89930,37 @@ msgid "" "[code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] " "specifies the stacking order of the canvas among those in the same layer." msgstr "" -"è®¾ç½®è§†çª—ç”»å¸ƒçš„å †å 顺åºã€‚\n" +"设置视å£ç”»å¸ƒçš„å †å 顺åºã€‚\n" "[code]layer[/code] 是实际的画布层,而 [code]sublayer[/code] 则指定画布在åŒä¸€" "层ä¸çš„å †å 顺åºã€‚" #: doc/classes/VisualServer.xml msgid "Sets the transformation of a viewport's canvas." -msgstr "设置视窗画布的å˜æ¢ã€‚" +msgstr "设置视å£ç”»å¸ƒçš„å˜æ¢ã€‚" #: doc/classes/VisualServer.xml msgid "" "Sets the clear mode of a viewport. See [enum ViewportClearMode] for options." -msgstr "设置视窗的清除模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportClearMode]。" +msgstr "设置视å£çš„清除模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportClearMode]。" #: doc/classes/VisualServer.xml msgid "" "Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for " "options." -msgstr "设置视窗的调试绘图模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportDebugDraw]。" +msgstr "设置视å£çš„调试绘图模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportDebugDraw]。" #: doc/classes/VisualServer.xml msgid "If [code]true[/code], a viewport's 3D rendering is disabled." -msgstr "如果为 [code]true[/code],则视窗的 3D 渲染将ç¦ç”¨ã€‚" +msgstr "如果为 [code]true[/code],则视å£çš„ 3D 渲染将ç¦ç”¨ã€‚" #: doc/classes/VisualServer.xml msgid "" "If [code]true[/code], rendering of a viewport's environment is disabled." -msgstr "如果为 [code]true[/code],则ç¦ç”¨è§†çª—环境的渲染。" +msgstr "如果为 [code]true[/code],则ç¦ç”¨è§†å£çŽ¯å¢ƒçš„渲染。" #: doc/classes/VisualServer.xml msgid "Sets the viewport's global transformation matrix." -msgstr "设置视窗的全局å˜æ¢çŸ©é˜µã€‚" +msgstr "设置视å£çš„全局å˜æ¢çŸ©é˜µã€‚" #: doc/classes/VisualServer.xml msgid "" @@ -89898,13 +89969,13 @@ msgid "" "viewport_set_use_32_bpc_depth].\n" "[b]Note:[/b] Only available on the GLES3 backend." msgstr "" -"如果为 [code]true[/code],该视区会渲染至高动æ€èŒƒå›´ï¼ˆHDR)而ä¸æ˜¯æ ‡å‡†åŠ¨æ€èŒƒå›´" +"如果为 [code]true[/code],该视å£ä¼šæ¸²æŸ“至高动æ€èŒƒå›´ï¼ˆHDR)而ä¸æ˜¯æ ‡å‡†åŠ¨æ€èŒƒå›´" "(SDR)。å¦è¯·å‚阅 [method viewport_set_use_32_bpc_depth]。\n" "[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚" #: doc/classes/VisualServer.xml msgid "If [code]true[/code], the viewport's canvas is not rendered." -msgstr "如果为 [code]true[/code],则ä¸æ¸²æŸ“视窗的画布。" +msgstr "如果为 [code]true[/code],则ä¸æ¸²æŸ“视å£çš„画布。" #: doc/classes/VisualServer.xml msgid "Currently unimplemented in Godot 3.x." @@ -89916,7 +89987,7 @@ msgstr "设置抗锯齿模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportMSAA]。" #: doc/classes/VisualServer.xml msgid "Sets the viewport's parent to another viewport." -msgstr "设置视窗的父视窗到å¦ä¸€ä¸ªè§†çª—。" +msgstr "设置视å£çš„父视å£åˆ°å¦ä¸€ä¸ªè§†å£ã€‚" #: doc/classes/VisualServer.xml msgid "" @@ -89933,12 +90004,12 @@ msgid "" "will be drawn, no automatic scaling is possible, even if your game scene is " "significantly larger than the window size." msgstr "" -"如果为 [code]true[/code],直接将视窗的内容渲染到å±å¹•ä¸Šã€‚è¿™å…许一个低级别的优" -"åŒ–ï¼Œä½ å¯ä»¥è·³è¿‡ç»˜åˆ¶è§†çª—åˆ°æ ¹è§†çª—ã€‚è™½ç„¶è¿™ç§ä¼˜åŒ–å¯ä»¥æ˜¾è‘—æ高速度(特别是在旧设备" -"上),但它是以牺牲å¯ç”¨æ€§ä¸ºä»£ä»·çš„。当å¯ç”¨è¿™ä¸ªåŠŸèƒ½æ—¶ï¼Œä½ ä¸èƒ½ä»Žè§†çª—或" +"如果为 [code]true[/code],直接将视å£çš„内容渲染到å±å¹•ä¸Šã€‚è¿™å…许一个低级别的优" +"åŒ–ï¼Œä½ å¯ä»¥è·³è¿‡ç»˜åˆ¶è§†å£åˆ°æ ¹è§†å£ã€‚虽然这ç§ä¼˜åŒ–å¯ä»¥æ˜¾è‘—æ高速度(特别是在旧设备" +"上),但它是以牺牲å¯ç”¨æ€§ä¸ºä»£ä»·çš„。当å¯ç”¨è¿™ä¸ªåŠŸèƒ½æ—¶ï¼Œä½ ä¸èƒ½ä»Žè§†å£æˆ–" "[code]SCREEN_TEXTURE[/code]ä¸è¯»å–ã€‚ä½ ä¹Ÿä¼šå¤±åŽ»æŸäº›çª—å£è®¾ç½®çš„好处,比如å„ç§æ‹‰ä¼¸" "模å¼ã€‚å¦ä¸€ä¸ªéœ€è¦æ³¨æ„çš„åŽæžœæ˜¯ï¼Œåœ¨2Dä¸ï¼Œæ¸²æŸ“是以窗å£åæ ‡è¿›è¡Œçš„ï¼Œæ‰€ä»¥å¦‚æžœä½ æœ‰ä¸€" -"个两å€äºŽçª—å£å¤§å°çš„è§†çª—ï¼Œå¹¶ä¸”ä½ è®¾ç½®äº†è¿™ä¸ªï¼Œé‚£ä¹ˆåªæœ‰é€‚åˆçª—å£çš„部分æ‰ä¼šè¢«ç»˜åˆ¶ï¼Œ" +"个两å€äºŽçª—å£å¤§å°çš„视å£ï¼Œå¹¶ä¸”ä½ è®¾ç½®äº†è¿™ä¸ªï¼Œé‚£ä¹ˆåªæœ‰é€‚åˆçª—å£çš„部分æ‰ä¼šè¢«ç»˜åˆ¶ï¼Œ" "没有自动缩放的å¯èƒ½ï¼Œå³ä½¿ä½ 的游æˆåœºæ™¯æ˜Žæ˜¾å¤§äºŽçª—å£å¤§å°ã€‚" #: doc/classes/VisualServer.xml @@ -89947,7 +90018,7 @@ msgid "" "The scenario contains information about the [enum ScenarioDebugMode], " "environment information, reflection atlas etc." msgstr "" -"设置一个视窗的场景。\n" +"设置视å£çš„场景。\n" "åœºæ™¯åŒ…å« [enum ScenarioDebugMode] çš„ä¿¡æ¯ã€çŽ¯å¢ƒä¿¡æ¯ã€å射图集ç‰ã€‚" #: doc/classes/VisualServer.xml @@ -89971,31 +90042,31 @@ msgid "" "[code]0.5[/code] generally give the best results. See also [method " "viewport_set_use_fxaa]." msgstr "" -"为视窗[code]viewport[/code]设定é”化强度[code]intensity[/code]。如果设置为大于" -"[code]0.0[/code]的值,对比度适应性é”化将被应用到3D视窗ä¸ã€‚这具有较低的性能æˆ" +"为视å£[code]viewport[/code]设定é”化强度[code]intensity[/code]。如果设置为大于" +"[code]0.0[/code]的值,对比度适应性é”化将被应用到3D视å£ä¸ã€‚这具有较低的性能æˆ" "本,å¯ä»¥ç”¨æ¥æ¢å¤ä½¿ç”¨FXAAæ—¶æŸå¤±çš„一些é”度。一般æ¥è¯´ï¼Œ[code]0.5[/code]å·¦å³çš„值" "å¯ä»¥å¾—到最好的效果。å‚阅[method viewport_set_use_fxaa]。" #: doc/classes/VisualServer.xml msgid "Sets the viewport's width and height." -msgstr "设置视窗的宽度和高度。" +msgstr "设置视å£çš„宽度和高度。" #: doc/classes/VisualServer.xml msgid "" "If [code]true[/code], the viewport renders its background as transparent." -msgstr "如果为 [code]true[/code],视窗将其背景渲染为é€æ˜Žã€‚" +msgstr "如果为 [code]true[/code],视å£å°†å…¶èƒŒæ™¯æ¸²æŸ“为é€æ˜Žã€‚" #: doc/classes/VisualServer.xml msgid "" "Sets when the viewport should be updated. See [enum ViewportUpdateMode] " "constants for options." -msgstr "设置应更新视窗的时间。å¯é€‰é¡¹è¯·å‚阅 [enum ViewportUpdateMode] 。" +msgstr "设置应更新视å£çš„时间。å¯é€‰é¡¹è¯·å‚阅 [enum ViewportUpdateMode] 。" #: doc/classes/VisualServer.xml msgid "" "Sets the viewport's 2D/3D mode. See [enum ViewportUsage] constants for " "options." -msgstr "设置视窗的 2D/3D 模å¼ã€‚é€‰é¡¹è§ [enum ViewportUsage] 常é‡ã€‚" +msgstr "设置视å£çš„ 2D/3D 模å¼ã€‚é€‰é¡¹è§ [enum ViewportUsage] 常é‡ã€‚" #: doc/classes/VisualServer.xml msgid "" @@ -90005,7 +90076,7 @@ msgid "" "on the same [Viewport] to set HDR to [code]true[/code].\n" "[b]Note:[/b] Only available on the GLES3 backend." msgstr "" -"如果为 [code]true[/code],分é…该视区的帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ" +"如果为 [code]true[/code],分é…该视å£çš„帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ" "ä¸æ˜¯åŠæµ®ç‚¹æ•°ç²¾åº¦ï¼ˆ16 ä½ï¼‰ã€‚åªæœ‰åœ¨åŒä¸€ä¸ª [Viewport] 上通过 [method " "viewport_set_use_32_bpc_depth] å°† HDR 设为 [code]true[/code] 时有效。\n" "[b]注æ„:[/b]仅在 GLES3 åŽç«¯ä¸å¯ç”¨ã€‚" @@ -90015,7 +90086,7 @@ msgid "" "If [code]true[/code], the viewport uses augmented or virtual reality " "technologies. See [ARVRInterface]." msgstr "" -"如果为 [code]true[/code]ï¼Œåˆ™è§†çª—ä½¿ç”¨å¢žå¼ºæˆ–è™šæ‹ŸçŽ°å®žæŠ€æœ¯ã€‚è§ [ARVRInterface]。" +"如果为 [code]true[/code],则视å£ä½¿ç”¨å¢žå¼ºæˆ–è™šæ‹ŸçŽ°å®žæŠ€æœ¯ã€‚è§ [ARVRInterface]。" #: doc/classes/VisualServer.xml msgid "" @@ -90042,14 +90113,14 @@ msgid "" "recovered by enabling contrast-adaptive sharpening (see [method " "viewport_set_sharpen_intensity])." msgstr "" -"å¯ç”¨è¯¥è§†çª—的快速近似抗锯齿。FXAA 是一ç§æµè¡Œçš„å±å¹•ç©ºé—´æŠ—锯齿方法,它速度快,但" +"å¯ç”¨è¯¥è§†å£çš„快速近似抗锯齿。FXAA 是一ç§æµè¡Œçš„å±å¹•ç©ºé—´æŠ—锯齿方法,它速度快,但" "会使图åƒçœ‹èµ·æ¥å¾ˆæ¨¡ç³Šï¼Œç‰¹åˆ«æ˜¯åœ¨ä½Žåˆ†è¾¨çŽ‡ä¸‹ã€‚在 1440p å’Œ 4K ç‰é«˜åˆ†è¾¨çŽ‡ä¸‹ï¼Œå®ƒä»ç„¶" "å¯ä»¥å·¥ä½œå¾—比较好。一些æŸå¤±çš„é”度å¯ä»¥é€šè¿‡å¯ç”¨å¯¹æ¯”度适应性é”化æ¥æ¢å¤ï¼ˆè§ " "[method viewport_set_sharpen_intensity])。" #: doc/classes/VisualServer.xml msgid "If [code]true[/code], the viewport's rendering is flipped vertically." -msgstr "如果为 [code]true[/code],则视窗的渲染垂直翻转。" +msgstr "如果为 [code]true[/code],则视å£çš„渲染垂直翻转。" #: doc/classes/VisualServer.xml msgid "" @@ -90440,33 +90511,33 @@ msgstr "优化阴影贴图的使用,æ高有效分辨率。但å¯èƒ½ä¼šå¯¼è‡´ #: doc/classes/VisualServer.xml msgid "Do not update the viewport." -msgstr "ä¸è¦æ›´æ–°è§†çª—。" +msgstr "ä¸è¦æ›´æ–°è§†å£ã€‚" #: doc/classes/VisualServer.xml msgid "Update the viewport once then set to disabled." -msgstr "更新一次视窗,然åŽè®¾ç½®ä¸ºç¦ç”¨ã€‚" +msgstr "更新一次视å£ï¼Œç„¶åŽè®¾ç½®ä¸ºç¦ç”¨ã€‚" #: doc/classes/VisualServer.xml msgid "Update the viewport whenever it is visible." -msgstr "åªè¦è§†çª—是å¯è§çš„,就更新视窗。" +msgstr "åªè¦è§†å£æ˜¯å¯è§çš„,就更新视å£ã€‚" #: doc/classes/VisualServer.xml msgid "Always update the viewport." -msgstr "始终更新视窗。" +msgstr "始终更新视å£ã€‚" #: doc/classes/VisualServer.xml msgid "The viewport is always cleared before drawing." -msgstr "在绘图之å‰ï¼Œè§†çª—总是被清空。" +msgstr "在绘图之å‰ï¼Œè§†å£æ€»æ˜¯è¢«æ¸…空。" #: doc/classes/VisualServer.xml msgid "The viewport is never cleared before drawing." -msgstr "在绘图之å‰ï¼Œè§†çª—永远ä¸ä¼šè¢«æ¸…空。" +msgstr "在绘图之å‰ï¼Œè§†å£æ°¸è¿œä¸ä¼šè¢«æ¸…空。" #: doc/classes/VisualServer.xml msgid "" "The viewport is cleared once, then the clear mode is set to [constant " "VIEWPORT_CLEAR_NEVER]." -msgstr "视窗被清除一次,然åŽæ¸…除模å¼è®¾ç½®ä¸º [constant VIEWPORT_CLEAR_NEVER]。" +msgstr "视å£è¢«æ¸…除一次,然åŽæ¸…除模å¼è®¾ç½®ä¸º [constant VIEWPORT_CLEAR_NEVER]。" #: doc/classes/VisualServer.xml msgid "Multisample antialiasing is disabled." @@ -92375,7 +92446,7 @@ msgstr "使用给定的纹ç†ä½œä¸ºæ¤å‡½æ•°çš„å‚数。" #: doc/classes/VisualShaderNodeTexture.xml msgid "Use the current viewport's texture as the source." -msgstr "使用当å‰è§†çª—的纹ç†ä½œä¸ºæºã€‚" +msgstr "使用当å‰è§†å£çš„纹ç†ä½œä¸ºæºã€‚" #: doc/classes/VisualShaderNodeTexture.xml msgid "" diff --git a/doc/translations/zh_TW.po b/doc/translations/zh_TW.po index a64bd25054..a21d110c05 100644 --- a/doc/translations/zh_TW.po +++ b/doc/translations/zh_TW.po @@ -15,12 +15,14 @@ # Otis Kao <momoslim@gmail.com>, 2022. # YuChiang Chang <chiang.c.tw@gmail.com>, 2022. # Hugel <qihu@nfschina.com>, 2022. +# Chih Wei Chien <dppss92132@gmail.com>, 2022. +# Edison Lee <edisonlee@edisonlee55.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine class reference\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-10-12 06:50+0000\n" -"Last-Translator: BinotaLIU <me@binota.org>\n" +"PO-Revision-Date: 2023-01-15 03:49+0000\n" +"Last-Translator: Edison Lee <edisonlee@edisonlee55.com>\n" "Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/" "godot-engine/godot-class-reference/zh_Hant/>\n" "Language: zh_TW\n" @@ -28,7 +30,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: doc/tools/make_rst.py msgid "Description" @@ -84,7 +86,7 @@ msgstr "繼承自:" #: doc/tools/make_rst.py msgid "(overrides %s)" -msgstr "" +msgstr "(覆寫 %s)" #: doc/tools/make_rst.py msgid "Default" @@ -126,13 +128,13 @@ msgstr "æ¤æ–¹æ³•ç”¨æ–¼å»ºæ§‹åž‹åˆ¥ã€‚" msgid "" "This method doesn't need an instance to be called, so it can be called " "directly using the class name." -msgstr "" +msgstr "該方法ä¸éœ€è¦ä½¿ç”¨ä¸€å€‹å¯¦é«”來呼å«ï¼Œæ‰€ä»¥ä»–å¯ä»¥ç›´æŽ¥ä½¿ç”¨ class name 呼å«ã€‚" #: doc/tools/make_rst.py msgid "" "This method describes a valid operator to use with this type as left-hand " "operand." -msgstr "" +msgstr "該方法æ述一個有效的é‹ç®—å使用æ¤åž‹åˆ¥ä½œç‚ºå·¦é‹ç®—值。" #: modules/gdscript/doc_classes/@GDScript.xml msgid "Built-in GDScript functions." @@ -148,7 +150,6 @@ msgstr "" "供。 (é—œéµå—:內建ã€å…¨åŸŸå‡½å¼ã€buildinã€build inã€global functions)" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns a color constructed from integer red, green, blue, and alpha " "channels. Each channel should have 8 bits of information ranging from 0 to " @@ -161,12 +162,12 @@ msgid "" "red = Color8(255, 0, 0)\n" "[/codeblock]" msgstr "" -"回傳以整數紅色ã€ç¶ 色ã€è—色與 Alpha 通é“構æˆçš„色彩。æ¯å€‹é€šé“éƒ½æ‡‰åŒ…å« 0 至 255 " -"çš„ 8 ä½å…ƒè³‡è¨Šã€‚\n" +"回傳以整數紅色ã€ç¶ 色ã€è—色與é€æ˜Žé€šé“構æˆçš„色彩。æ¯å€‹é€šé“éƒ½æ‡‰åŒ…å« 0 至 255 çš„ " +"8 ä½å…ƒè³‡è¨Šã€‚\n" "[code]r8[/code] 紅色通é“\n" "[code]g8[/code] ç¶ è‰²é€šé“\n" "[code]b8[/code] è—色通é“\n" -"[code]a8[/code] Alpha 通é“\n" +"[code]a8[/code] é€æ˜Žé€šé“\n" "[codeblock]\n" "red = Color8(255, 0, 0)\n" "[/codeblock]" @@ -201,7 +202,6 @@ msgstr "" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns the arc cosine of [code]s[/code] in radians. Use to get the angle of " "cosine [code]s[/code]. [code]s[/code] must be between [code]-1.0[/code] and " @@ -212,15 +212,15 @@ msgid "" "c = acos(0.866025)\n" "[/codeblock]" msgstr "" -"回傳以弧度表示的[code]s[/code]çš„å餘弦(cos)值。用於求餘弦(sin)值[code]s[/" -"code]的夾角。\n" +"回傳以弧度表示的[code]s[/code]çš„å餘弦(arc cos)值。用於求餘弦(cos)值[code]s[/" +"code]的夾角。[code]s[/code]å¿…é ˆä»‹æ–¼[code]-1.0[/code]與[code]1.0[/code]之間 " +"(包å«),å¦å‰‡ [method acos] 會回傳 [constant NAN]。\n" "[codeblock]\n" -"# c 為0.523599,若以rad2deg(s)æ›ç®—,則為30度\n" +"# c 為 0.523599,若以 rad2deg(s) æ›ç®—,則為30度\n" "c = acos(0.866025)\n" "[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml -#, fuzzy msgid "" "Returns the arc sine of [code]s[/code] in radians. Use to get the angle of " "sine [code]s[/code]. [code]s[/code] must be between [code]-1.0[/code] and " @@ -230,7 +230,14 @@ msgid "" "# s is 0.523599 or 30 degrees if converted with rad2deg(s)\n" "s = asin(0.5)\n" "[/codeblock]" -msgstr "testing" +msgstr "" +"回傳以弧度表示的[code]s[/code]çš„åæ£å¼¦(arc sin)值。用於求æ£å¼¦ (sin) 值" +"[code]s[/code]的夾角。[code]s[/code]å¿…é ˆä»‹æ–¼[code]-1.0[/code]與[code]1.0[/" +"code]之間 (包å«),å¦å‰‡ [method asin] 會回傳 [constant NAN]。\n" +"[codeblock]\n" +"# c 為 0.523599,若以 rad2deg(s) æ›ç®—,則為 30 度\n" +"c = asin(0.5)\n" +"[/codeblock]" #: modules/gdscript/doc_classes/@GDScript.xml #, fuzzy @@ -30066,7 +30073,11 @@ msgid "" "using an [AnimatedTexture], only the first frame will be displayed.\n" "[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or " "[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] " -"compression mode can't be used for custom cursors." +"compression mode can't be used for custom cursors.\n" +"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is " +"128×128. Cursor images larger than 32×32 will also only be displayed if the " +"mouse cursor image is entirely located within the page for [url=https://" +"chromestatus.com/feature/5825971391299584]security reasons[/url]." msgstr "" #: doc/classes/Input.xml @@ -41853,7 +41864,7 @@ msgstr "" #: doc/classes/OS.xml msgid "Desktop directory path." -msgstr "" +msgstr "æ¡Œé¢è³‡æ–™å¤¾è·¯å¾‘。" #: doc/classes/OS.xml msgid "DCIM (Digital Camera Images) directory path." @@ -41861,27 +41872,27 @@ msgstr "" #: doc/classes/OS.xml msgid "Documents directory path." -msgstr "" +msgstr "檔案資料夾路徑。" #: doc/classes/OS.xml msgid "Downloads directory path." -msgstr "" +msgstr "下載資料夾路徑。" #: doc/classes/OS.xml msgid "Movies directory path." -msgstr "" +msgstr "影片資料夾路徑。" #: doc/classes/OS.xml msgid "Music directory path." -msgstr "" +msgstr "音樂資料夾路徑。" #: doc/classes/OS.xml msgid "Pictures directory path." -msgstr "" +msgstr "圖片資料夾路徑。" #: doc/classes/OS.xml msgid "Ringtones directory path." -msgstr "" +msgstr "鈴è²è³‡æ–™å¤¾è·¯å¾‘。" #: doc/classes/OS.xml msgid "Unknown powerstate." diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 966a09c6c2..219529d2f6 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -632,7 +632,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { ERR_FAIL_COND(result != noErr); if (capture) { - // Reset audio input to keep synchronisation. + // Reset audio input to keep synchronization. input_position = 0; input_size = 0; } diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 2887b6b44f..89b1c1889e 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -803,7 +803,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend light_count++; - if (light_count == data.max_lights_per_item) { + if (light_count == data.max_lights_per_item - 1) { break; } } @@ -905,10 +905,12 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend if (rect->flags & CANVAS_RECT_FLIP_H) { src_rect.size.x *= -1; + state.instance_data_array[r_index].flags |= FLAGS_FLIP_H; } if (rect->flags & CANVAS_RECT_FLIP_V) { src_rect.size.y *= -1; + state.instance_data_array[r_index].flags |= FLAGS_FLIP_V; } if (rect->flags & CANVAS_RECT_TRANSPOSE) { @@ -2652,8 +2654,10 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() { shader_type canvas_item; +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + void fragment() { - vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0); + vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0); if (c.a > 0.0001) { c.rgb /= c.a; @@ -2677,8 +2681,10 @@ void fragment() { shader_type canvas_item; +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + void fragment() { - vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0); + vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0); COLOR.rgb = c.rgb; } )"); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index db9203b249..916e12057c 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -75,6 +75,9 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender { FLAGS_USE_MSDF = (1 << 28), FLAGS_USE_LCD = (1 << 29), + + FLAGS_FLIP_H = (1 << 30), + FLAGS_FLIP_V = (1 << 31), }; enum { diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index e4bcc424b3..9547435607 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1535,8 +1535,6 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b } } - li->gl_id = r_omni_light_count; - scene_state.omni_light_sort[r_omni_light_count].instance = li; scene_state.omni_light_sort[r_omni_light_count].depth = distance; r_omni_light_count++; @@ -1560,8 +1558,6 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b } } - li->gl_id = r_spot_light_count; - scene_state.spot_light_sort[r_spot_light_count].instance = li; scene_state.spot_light_sort[r_spot_light_count].depth = distance; r_spot_light_count++; @@ -1584,8 +1580,11 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index]; RS::LightType type = (i < r_omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; GLES3::LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance; + real_t distance = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].depth : scene_state.spot_light_sort[index].depth; RID base = li->light; + li->gl_id = index; + Transform3D light_transform = li->transform; Vector3 pos = inverse_transform.xform(light_transform.origin); @@ -1612,13 +1611,11 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b // Reuse fade begin, fade length and distance for shadow LOD determination later. float fade_begin = 0.0; float fade_length = 0.0; - real_t distance = 0.0; float fade = 1.0; if (light_storage->light_is_distance_fade_enabled(li->light)) { fade_begin = light_storage->light_get_distance_fade_begin(li->light); fade_length = light_storage->light_get_distance_fade_length(li->light); - distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin); if (distance > fade_begin) { // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 9a90f33674..1631c65385 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -277,7 +277,7 @@ flat in uvec4 varying_G; uniform sampler2D atlas_texture; //texunit:-2 uniform sampler2D shadow_atlas_texture; //texunit:-3 #endif // DISABLE_LIGHTING -uniform sampler2D screen_texture; //texunit:-4 +uniform sampler2D color_buffer; //texunit:-4 uniform sampler2D sdf_texture; //texunit:-5 uniform sampler2D normal_texture; //texunit:-6 uniform sampler2D specular_texture; //texunit:-7 @@ -579,6 +579,12 @@ void main() { if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); + if (bool(read_draw_data_flags & FLAGS_FLIP_H)) { + normal.x = -normal.x; + } + if (bool(read_draw_data_flags & FLAGS_FLIP_V)) { + normal.y = -normal.y; + } normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; } else { diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl index f65558f042..d53c0fcb26 100644 --- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl +++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl @@ -27,6 +27,9 @@ #define FLAGS_USE_MSDF uint(1 << 28) #define FLAGS_USE_LCD uint(1 << 29) +#define FLAGS_FLIP_H uint(1 << 30) +#define FLAGS_FLIP_V uint(1 << 31) + layout(std140) uniform GlobalShaderUniformData { //ubo:1 vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS]; }; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 1b922fa726..951155e287 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -564,10 +564,10 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4 #ifdef USE_MULTIVIEW uniform highp sampler2DArray depth_buffer; // texunit:-6 -uniform highp sampler2DArray screen_texture; // texunit:-5 +uniform highp sampler2DArray color_buffer; // texunit:-5 #else uniform highp sampler2D depth_buffer; // texunit:-6 -uniform highp sampler2D screen_texture; // texunit:-5 +uniform highp sampler2D color_buffer; // texunit:-5 #endif uniform highp mat4 world_transform; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 2d81771898..50e5c868d3 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1515,7 +1515,6 @@ MaterialStorage::MaterialStorage() { actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture"; actions.renames["SPECULAR_SHININESS"] = "specular_shininess"; actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "screen_texture"; actions.renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["POINT_COORD"] = "gl_PointCoord"; @@ -1536,7 +1535,6 @@ MaterialStorage::MaterialStorage() { actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; @@ -1617,9 +1615,6 @@ MaterialStorage::MaterialStorage() { actions.renames["POINT_COORD"] = "gl_PointCoord"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; actions.renames["SCREEN_UV"] = "screen_uv"; - //actions.renames["SCREEN_TEXTURE"] = "color_buffer"; //Not implemented in 3D yet. - //actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; // Not implemented in 3D yet. - //actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; // Not implemented in 3D yet actions.renames["DEPTH"] = "gl_FragDepth"; actions.renames["OUTPUT_IS_SRGB"] = "true"; actions.renames["FOG"] = "fog"; @@ -1684,7 +1679,6 @@ MaterialStorage::MaterialStorage() { actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; @@ -2960,7 +2954,6 @@ void CanvasShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PMALPHA); actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED); - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; actions.usage_flag_pointers["TIME"] = &uses_time; @@ -2974,6 +2967,7 @@ void CanvasShaderData::set_code(const String &p_code) { blend_mode = BlendMode(blend_modei); uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps; + uses_screen_texture = gen_code.uses_screen_texture; #if 0 print_line("**compiling shader:"); @@ -3309,9 +3303,6 @@ void SceneShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; - actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; actions.usage_flag_pointers["DISCARD"] = &uses_discard; actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; @@ -3364,6 +3355,9 @@ void SceneShaderData::set_code(const String &p_code) { vertex_input_mask |= uses_bones << 9; vertex_input_mask |= uses_weights << 10; uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps; + uses_screen_texture = gen_code.uses_screen_texture; + uses_depth_texture = gen_code.uses_depth_texture; + uses_normal_texture = gen_code.uses_normal_roughness_texture; uses_vertex_time = gen_code.uses_vertex_time; uses_fragment_time = gen_code.uses_fragment_time; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 489c328f64..67526bc003 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -567,23 +567,29 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I } } break; case Image::FORMAT_ETC2_RA_AS_RG: { +#ifndef WEB_ENABLED if (config->etc2_supported) { r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - } else { + } else +#endif + { need_decompress = true; } decompress_ra_to_rg = true; } break; case Image::FORMAT_DXT5_RA_AS_RG: { +#ifndef WEB_ENABLED if (config->s3tc_supported) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - } else { + } else +#endif + { need_decompress = true; } decompress_ra_to_rg = true; @@ -1137,6 +1143,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST); texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +#ifndef WEB_ENABLED switch (texture->format) { #ifdef GLES_OVER_GL case Image::FORMAT_L8: { @@ -1151,7 +1158,8 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN); } break; -#endif +#endif // GLES3_OVER_GL + case Image::FORMAT_ETC2_RA_AS_RG: case Image::FORMAT_DXT5_RA_AS_RG: { glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); @@ -1172,6 +1180,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); } break; } +#endif // WEB_ENABLED int mipmaps = img->has_mipmaps() ? img->get_mipmap_count() + 1 : 1; @@ -1525,18 +1534,6 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const { return AABB(); } -/* DECAL INSTANCE API */ - -RID TextureStorage::decal_instance_create(RID p_decal) { - return RID(); -} - -void TextureStorage::decal_instance_free(RID p_decal_instance) { -} - -void TextureStorage::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { -} - /* RENDER TARGET API */ GLuint TextureStorage::system_fbo = 0; @@ -1599,9 +1596,13 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } +#ifndef IOS_ENABLED if (use_multiview) { glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count); } else { +#else + { +#endif glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); } @@ -1626,9 +1627,13 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } +#ifndef IOS_ENABLED if (use_multiview) { glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count); } else { +#else + { +#endif glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); } diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 9ffe16fd16..9d3f407226 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -561,9 +561,10 @@ public: /* DECAL INSTANCE */ - virtual RID decal_instance_create(RID p_decal) override; - virtual void decal_instance_free(RID p_decal_instance) override; - virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; + virtual RID decal_instance_create(RID p_decal) override { return RID(); } + virtual void decal_instance_free(RID p_decal_instance) override {} + virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {} + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {} /* RENDER TARGET API */ diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 1c1255ce98..e14c3c7f7a 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -264,7 +264,7 @@ Error AudioDriverPulseAudio::init_device() { samples_in.resize(buffer_frames * channels); samples_out.resize(pa_buffer_size); - // Reset audio input to keep synchronisation. + // Reset audio input to keep synchronization. input_position = 0; input_size = 0; diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 557060c907..a162f46103 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -189,7 +189,7 @@ void DirAccessUnix::list_dir_end() { _cisdir = false; } -#if defined(HAVE_MNTENT) && defined(X11_ENABLED) +#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED) static bool _filter_drive(struct mntent *mnt) { // Ignore devices that don't point to /dev if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) { @@ -213,7 +213,7 @@ static void _get_drives(List<String> *list) { // Add root. list->push_back("/"); -#if defined(HAVE_MNTENT) && defined(X11_ENABLED) +#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED) // Check /etc/mtab for the list of mounted partitions. FILE *mtab = setmntent("/etc/mtab", "r"); if (mtab) { diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index c37b3d9c87..178f01b185 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -411,10 +411,6 @@ bool OS_Unix::is_process_running(const ProcessID &p_pid) const { return true; } -bool OS_Unix::has_environment(const String &p_var) const { - return getenv(p_var.utf8().get_data()) != nullptr; -} - String OS_Unix::get_locale() const { if (!has_environment("LANG")) { return "en"; @@ -487,6 +483,10 @@ Error OS_Unix::set_cwd(const String &p_cwd) { return OK; } +bool OS_Unix::has_environment(const String &p_var) const { + return getenv(p_var.utf8().get_data()) != nullptr; +} + String OS_Unix::get_environment(const String &p_var) const { if (getenv(p_var.utf8().get_data())) { return getenv(p_var.utf8().get_data()); @@ -494,8 +494,15 @@ String OS_Unix::get_environment(const String &p_var) const { return ""; } -bool OS_Unix::set_environment(const String &p_var, const String &p_value) const { - return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0; +void OS_Unix::set_environment(const String &p_var, const String &p_value) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + int err = setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ 1); + ERR_FAIL_COND_MSG(err != 0, vformat("Failed setting environment variable '%s', the system is out of memory.", p_var)); +} + +void OS_Unix::unset_environment(const String &p_var) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + unsetenv(p_var.utf8().get_data()); } String OS_Unix::get_user_data_dir() const { diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 416311307c..03429622ae 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -81,7 +81,9 @@ public: virtual bool has_environment(const String &p_var) const override; virtual String get_environment(const String &p_var) const override; - virtual bool set_environment(const String &p_var, const String &p_value) const override; + virtual void set_environment(const String &p_var, const String &p_value) const override; + virtual void unset_environment(const String &p_var) const override; + virtual String get_locale() const override; virtual void initialize_debugging() override; diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 0bccefede8..b5b00fd71e 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -353,11 +353,11 @@ Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const cha ERR_FAIL_V(ERR_CANT_CREATE); } - for (uint32_t i = 0; i < instance_validation_layers_alt.size(); i++) { - if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].ptr(), instance_layer_count, instance_layers)) { - *count = instance_validation_layers_alt[i].size(); + for (const LocalVector<const char *> &layer : instance_validation_layers_alt) { + if (_check_layers(layer.size(), layer.ptr(), instance_layer_count, instance_layers)) { + *count = layer.size(); if (names != nullptr) { - *names = instance_validation_layers_alt[i].ptr(); + *names = layer.ptr(); } break; } @@ -2252,7 +2252,7 @@ Error VulkanContext::swap_buffers() { // simple that it doesn't do either of those. } #endif - // Wait for the image acquired semaphore to be signalled to ensure + // Wait for the image acquired semaphore to be signaled to ensure // that the image won't be rendered to until the presentation // engine has fully released ownership to the application, and it is // okay to render to the image. @@ -2304,7 +2304,7 @@ Error VulkanContext::swap_buffers() { if (separate_present_queue) { // If we are using separate queues, change image ownership to the // present queue before presenting, waiting for the draw complete - // semaphore and signalling the ownership released semaphore when finished. + // semaphore and signaling the ownership released semaphore when finished. VkFence nullFence = VK_NULL_HANDLE; pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = 1; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 37a94ce4cc..ea40622afc 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -34,7 +34,6 @@ #include "core/os/os.h" #include "core/string/print_string.h" - #include <share.h> // _SH_DENYNO #include <shlwapi.h> #define WIN32_LEAN_AND_MEAN @@ -58,7 +57,27 @@ void FileAccessWindows::check_errors() const { } } +bool FileAccessWindows::is_path_invalid(const String &p_path) { + // Check for invalid operating system file. + String fname = p_path; + int dot = fname.find("."); + if (dot != -1) { + fname = fname.substr(0, dot); + } + fname = fname.to_lower(); + return invalid_files.has(fname); +} + Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { + if (is_path_invalid(p_path)) { +#ifdef DEBUG_ENABLED + if (p_mode_flags != READ) { + WARN_PRINT("The path :" + p_path + " is a reserved Windows system pipe, so it can't be used for creating files."); + } +#endif + return ERR_INVALID_PARAMETER; + } + _close(); path_src = p_path; @@ -313,6 +332,10 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { } bool FileAccessWindows::file_exists(const String &p_name) { + if (is_path_invalid(p_name)) { + return false; + } + String filename = fix_path(p_name); FILE *g = _wfsopen((LPCWSTR)(filename.utf16().get_data()), L"rb", _SH_DENYNO); if (g == nullptr) { @@ -324,6 +347,10 @@ bool FileAccessWindows::file_exists(const String &p_name) { } uint64_t FileAccessWindows::_get_modified_time(const String &p_file) { + if (is_path_invalid(p_file)) { + return 0; + } + String file = fix_path(p_file); if (file.ends_with("/") && file != "/") { file = file.substr(0, file.length() - 1); @@ -352,4 +379,20 @@ FileAccessWindows::~FileAccessWindows() { _close(); } +HashSet<String> FileAccessWindows::invalid_files; + +void FileAccessWindows::initialize() { + static const char *reserved_files[]{ + "con", "prn", "aux", "nul", "com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", nullptr + }; + int reserved_file_index = 0; + while (reserved_files[reserved_file_index] != nullptr) { + invalid_files.insert(reserved_files[reserved_file_index]); + reserved_file_index++; + } +} +void FileAccessWindows::finalize() { + invalid_files.clear(); +} + #endif // WINDOWS_ENABLED diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 832cef3363..2b9960d494 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -50,6 +50,9 @@ class FileAccessWindows : public FileAccess { void _close(); + static bool is_path_invalid(const String &p_path); + static HashSet<String> invalid_files; + public: virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file virtual bool is_open() const override; ///< true when file is open @@ -79,6 +82,9 @@ public: virtual uint32_t _get_unix_permissions(const String &p_file) override; virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override; + static void initialize(); + static void finalize(); + FileAccessWindows() {} virtual ~FileAccessWindows(); }; diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 712b11d7d7..cb8d98932d 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -354,10 +354,6 @@ void ActionMapEditor::_notification(int p_what) { } void ActionMapEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ActionMapEditor::drop_data_fw); - ADD_SIGNAL(MethodInfo("action_added", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("action_edited", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::DICTIONARY, "new_action"))); ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::STRING, "name"))); @@ -578,7 +574,7 @@ ActionMapEditor::ActionMapEditor() { action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed)); main_vbox->add_child(action_tree); - action_tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(action_tree, ActionMapEditor); // Adding event dialog event_config_dialog = memnew(InputEventConfigurationDialog); diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp deleted file mode 100644 index dd27b61df9..0000000000 --- a/editor/array_property_edit.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/**************************************************************************/ -/* array_property_edit.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "array_property_edit.h" - -#include "core/io/marshalls.h" -#include "editor/editor_undo_redo_manager.h" - -#define ITEMS_PER_PAGE 100 - -Variant ArrayPropertyEdit::get_array() const { - Object *o = ObjectDB::get_instance(obj); - if (!o) { - return Array(); - } - Variant arr = o->get(property); - if (!arr.is_array()) { - Callable::CallError ce; - Variant::construct(default_type, arr, nullptr, 0, ce); - } - return arr; -} - -void ArrayPropertyEdit::_notif_change() { - notify_property_list_changed(); -} - -void ArrayPropertyEdit::_set_size(int p_size) { - Variant arr = get_array(); - arr.call("resize", p_size); - Object *o = ObjectDB::get_instance(obj); - if (!o) { - return; - } - - o->set(property, arr); -} - -void ArrayPropertyEdit::_set_value(int p_idx, const Variant &p_value) { - Variant arr = get_array(); - arr.set(p_idx, p_value); - Object *o = ObjectDB::get_instance(obj); - if (!o) { - return; - } - - o->set(property, arr); -} - -bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { - String pn = p_name; - - if (pn.begins_with("array/")) { - if (pn == "array/size") { - Variant arr = get_array(); - int size = arr.call("size"); - - int newsize = p_value; - if (newsize == size) { - return true; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Resize Array")); - ur->add_do_method(this, "_set_size", newsize); - ur->add_undo_method(this, "_set_size", size); - if (newsize < size) { - for (int i = newsize; i < size; i++) { - ur->add_undo_method(this, "_set_value", i, arr.get(i)); - } - } else if (newsize > size) { - Variant init; - Callable::CallError ce; - Variant::Type new_type = subtype; - if (new_type == Variant::NIL && size) { - new_type = arr.get(size - 1).get_type(); - } - if (new_type != Variant::NIL) { - Variant::construct(new_type, init, nullptr, 0, ce); - for (int i = size; i < newsize; i++) { - ur->add_do_method(this, "_set_value", i, init); - } - } - } - ur->add_do_method(this, "_notif_change"); - ur->add_undo_method(this, "_notif_change"); - ur->commit_action(); - return true; - } - if (pn == "array/page") { - page = p_value; - notify_property_list_changed(); - return true; - } - - } else if (pn.begins_with("indices")) { - if (pn.contains("_")) { - //type - int idx = pn.get_slicec('/', 1).get_slicec('_', 0).to_int(); - - int type = p_value; - - Variant arr = get_array(); - - Variant value = arr.get(idx); - if (value.get_type() != type && type >= 0 && type < Variant::VARIANT_MAX) { - Callable::CallError ce; - Variant new_value; - Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce); - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - - ur->create_action(TTR("Change Array Value Type")); - ur->add_do_method(this, "_set_value", idx, new_value); - ur->add_undo_method(this, "_set_value", idx, value); - ur->add_do_method(this, "_notif_change"); - ur->add_undo_method(this, "_notif_change"); - ur->commit_action(); - } - return true; - - } else { - int idx = pn.get_slicec('/', 1).to_int(); - Variant arr = get_array(); - - Variant value = arr.get(idx); - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - - ur->create_action(TTR("Change Array Value")); - ur->add_do_method(this, "_set_value", idx, p_value); - ur->add_undo_method(this, "_set_value", idx, value); - ur->commit_action(); - return true; - } - } - - return false; -} - -bool ArrayPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const { - Variant arr = get_array(); - //int size = arr.call("size"); - - String pn = p_name; - if (pn.begins_with("array/")) { - if (pn == "array/size") { - r_ret = arr.call("size"); - return true; - } - if (pn == "array/page") { - r_ret = page; - return true; - } - } else if (pn.begins_with("indices")) { - if (pn.contains("_")) { - //type - int idx = pn.get_slicec('/', 1).get_slicec('_', 0).to_int(); - bool valid; - r_ret = arr.get(idx, &valid); - if (valid) { - r_ret = r_ret.get_type(); - } - return valid; - - } else { - int idx = pn.get_slicec('/', 1).to_int(); - bool valid; - r_ret = arr.get(idx, &valid); - - if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) { - r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id(); - } - - return valid; - } - } - - return false; -} - -void ArrayPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const { - Variant arr = get_array(); - int size = arr.call("size"); - - p_list->push_back(PropertyInfo(Variant::INT, "array/size", PROPERTY_HINT_RANGE, "0,100000,1")); - int pages = size / ITEMS_PER_PAGE; - if (pages > 0) { - p_list->push_back(PropertyInfo(Variant::INT, "array/page", PROPERTY_HINT_RANGE, "0," + itos(pages) + ",1")); - } - - int offset = page * ITEMS_PER_PAGE; - - int items = MIN(size - offset, ITEMS_PER_PAGE); - - for (int i = 0; i < items; i++) { - Variant v = arr.get(i + offset); - bool is_typed = arr.get_type() != Variant::ARRAY || subtype != Variant::NIL; - - if (!is_typed) { - p_list->push_back(PropertyInfo(Variant::INT, "indices/" + itos(i + offset) + "_type", PROPERTY_HINT_ENUM, vtypes)); - } - - if (v.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(v)) { - p_list->push_back(PropertyInfo(Variant::INT, "indices/" + itos(i + offset), PROPERTY_HINT_OBJECT_ID, "Object")); - continue; - } - - if (is_typed || v.get_type() != Variant::NIL) { - PropertyInfo pi(v.get_type(), "indices/" + itos(i + offset)); - if (subtype != Variant::NIL) { - pi.type = Variant::Type(subtype); - pi.hint = PropertyHint(subtype_hint); - pi.hint_string = subtype_hint_string; - } else if (v.get_type() == Variant::OBJECT) { - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Resource"; - } - - p_list->push_back(pi); - } - } -} - -void ArrayPropertyEdit::edit(Object *p_obj, const StringName &p_prop, const String &p_hint_string, Variant::Type p_deftype) { - page = 0; - property = p_prop; - obj = p_obj->get_instance_id(); - default_type = p_deftype; - - if (!p_hint_string.is_empty()) { - int hint_subtype_separator = p_hint_string.find(":"); - if (hint_subtype_separator >= 0) { - String subtype_string = p_hint_string.substr(0, hint_subtype_separator); - - int slash_pos = subtype_string.find("/"); - if (slash_pos >= 0) { - subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int()); - subtype_string = subtype_string.substr(0, slash_pos); - } - - subtype_hint_string = p_hint_string.substr(hint_subtype_separator + 1, p_hint_string.size() - hint_subtype_separator - 1); - subtype = Variant::Type(subtype_string.to_int()); - } - } -} - -Node *ArrayPropertyEdit::get_node() { - return Object::cast_to<Node>(ObjectDB::get_instance(obj)); -} - -bool ArrayPropertyEdit::_dont_undo_redo() { - return true; -} - -void ArrayPropertyEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_set_size"), &ArrayPropertyEdit::_set_size); - ClassDB::bind_method(D_METHOD("_set_value"), &ArrayPropertyEdit::_set_value); - ClassDB::bind_method(D_METHOD("_notif_change"), &ArrayPropertyEdit::_notif_change); - ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &ArrayPropertyEdit::_dont_undo_redo); -} - -ArrayPropertyEdit::ArrayPropertyEdit() { - page = 0; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - vtypes += ","; - } - vtypes += Variant::get_type_name(Variant::Type(i)); - } - default_type = Variant::NIL; - subtype = Variant::NIL; - subtype_hint = PROPERTY_HINT_NONE; - subtype_hint_string = ""; -} diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index df8adf01e4..644735a4d8 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -2086,6 +2086,7 @@ CodeTextEditor::CodeTextEditor() { text_editor = memnew(CodeEdit); add_child(text_editor); text_editor->set_v_size_flags(SIZE_EXPAND_FILL); + text_editor->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_GDSCRIPT); int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures"); Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font")); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 03d2a6565a..9ff480f130 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -285,7 +285,7 @@ void ConnectDialog::_notification(int p_what) { Ref<StyleBox> style = get_theme_stylebox("normal", "LineEdit")->duplicate(); if (style.is_valid()) { - style->set_default_margin(SIDE_TOP, style->get_default_margin(SIDE_TOP) + 1.0); + style->set_content_margin(SIDE_TOP, style->get_content_margin(SIDE_TOP) + 1.0); from_signal->add_theme_style_override("normal", style); } } break; @@ -1196,6 +1196,7 @@ ConnectionsDock::ConnectionsDock() { tree->set_columns(1); tree->set_select_mode(Tree::SELECT_ROW); tree->set_hide_root(true); + tree->set_column_clip_content(0, true); vbc->add_child(tree); tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); tree->set_allow_rmb_select(true); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 98fcde17c4..0814d5b5ca 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -724,12 +724,6 @@ void CreateDialog::_load_favorites_and_history() { } void CreateDialog::_bind_methods() { - ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list); - - ClassDB::bind_method("_get_drag_data_fw", &CreateDialog::get_drag_data_fw); - ClassDB::bind_method("_can_drop_data_fw", &CreateDialog::can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &CreateDialog::drop_data_fw); - ADD_SIGNAL(MethodInfo("create")); ADD_SIGNAL(MethodInfo("favorites_updated")); } @@ -759,7 +753,7 @@ CreateDialog::CreateDialog() { favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected)); favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated)); favorites->add_theme_constant_override("draw_guides", 1); - favorites->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(favorites, CreateDialog); fav_vb->add_margin_child(TTR("Favorites:"), favorites, true); VBoxContainer *rec_vb = memnew(VBoxContainer); diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp deleted file mode 100644 index ad59a1c169..0000000000 --- a/editor/dictionary_property_edit.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/**************************************************************************/ -/* dictionary_property_edit.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "dictionary_property_edit.h" -#include "editor/editor_undo_redo_manager.h" - -void DictionaryPropertyEdit::_notif_change() { - notify_property_list_changed(); -} - -void DictionaryPropertyEdit::_set_key(const Variant &p_old_key, const Variant &p_new_key) { - // TODO: Set key of a dictionary is not allowed yet -} - -void DictionaryPropertyEdit::_set_value(const Variant &p_key, const Variant &p_value) { - Dictionary dict = get_dictionary(); - dict[p_key] = p_value; - Object *o = ObjectDB::get_instance(obj); - if (!o) { - return; - } - - o->set(property, dict); -} - -Variant DictionaryPropertyEdit::get_dictionary() const { - Object *o = ObjectDB::get_instance(obj); - if (!o) { - return Dictionary(); - } - Variant dict = o->get(property); - if (dict.get_type() != Variant::DICTIONARY) { - return Dictionary(); - } - return dict; -} - -void DictionaryPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const { - Dictionary dict = get_dictionary(); - - Array keys = dict.keys(); - keys.sort(); - - for (int i = 0; i < keys.size(); i++) { - String index = itos(i); - - const Variant &key = keys[i]; - PropertyInfo pi(key.get_type(), index + ": key"); - p_list->push_back(pi); - - const Variant &value = dict[key]; - pi = PropertyInfo(value.get_type(), index + ": value"); - p_list->push_back(pi); - } -} - -void DictionaryPropertyEdit::edit(Object *p_obj, const StringName &p_prop) { - property = p_prop; - obj = p_obj->get_instance_id(); -} - -Node *DictionaryPropertyEdit::get_node() { - Object *o = ObjectDB::get_instance(obj); - if (!o) { - return nullptr; - } - - return cast_to<Node>(o); -} - -bool DictionaryPropertyEdit::_dont_undo_redo() { - return true; -} - -void DictionaryPropertyEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_set_key"), &DictionaryPropertyEdit::_set_key); - ClassDB::bind_method(D_METHOD("_set_value"), &DictionaryPropertyEdit::_set_value); - ClassDB::bind_method(D_METHOD("_notif_change"), &DictionaryPropertyEdit::_notif_change); - ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &DictionaryPropertyEdit::_dont_undo_redo); -} - -bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { - Dictionary dict = get_dictionary(); - Array keys = dict.keys(); - keys.sort(); - - String pn = p_name; - int slash = pn.find(": "); - if (slash != -1 && pn.length() > slash) { - String type = pn.substr(slash + 2, pn.length()); - int index = pn.substr(0, slash).to_int(); - if (type == "key" && index < keys.size()) { - const Variant &key = keys[index]; - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - - ur->create_action(TTR("Change Dictionary Key")); - ur->add_do_method(this, "_set_key", key, p_value); - ur->add_undo_method(this, "_set_key", p_value, key); - ur->commit_action(); - - return true; - } else if (type == "value" && index < keys.size()) { - const Variant &key = keys[index]; - if (dict.has(key)) { - Variant value = dict[key]; - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - - ur->create_action(TTR("Change Dictionary Value")); - ur->add_do_method(this, "_set_value", key, p_value); - ur->add_undo_method(this, "_set_value", key, value); - ur->commit_action(); - - return true; - } - } - } - - return false; -} - -bool DictionaryPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const { - Dictionary dict = get_dictionary(); - Array keys = dict.keys(); - keys.sort(); - - String pn = p_name; - int slash = pn.find(": "); - - if (slash != -1 && pn.length() > slash) { - String type = pn.substr(slash + 2, pn.length()); - int index = pn.substr(0, slash).to_int(); - - if (type == "key" && index < keys.size()) { - r_ret = keys[index]; - return true; - } else if (type == "value" && index < keys.size()) { - const Variant &key = keys[index]; - if (dict.has(key)) { - r_ret = dict[key]; - return true; - } - } - } - - return false; -} - -DictionaryPropertyEdit::DictionaryPropertyEdit() { -} diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 85adc312f2..5bdef32c60 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -750,6 +750,7 @@ void DocTools::generate(bool p_basic_types) { MethodInfo mi; mi.name = "operator []"; mi.return_val.type = Variant::get_indexed_element_type(Variant::Type(i)); + mi.return_val.usage = Variant::get_indexed_element_usage(Variant::Type(i)); PropertyInfo arg; arg.name = "index"; arg.type = Variant::INT; @@ -1021,15 +1022,15 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & if (parser->get_node_name() == element) { DocData::MethodDoc method; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); - method.name = parser->get_attribute_value("name"); + method.name = parser->get_named_attribute_value("name"); if (parser->has_attribute("qualifiers")) { - method.qualifiers = parser->get_attribute_value("qualifiers"); + method.qualifiers = parser->get_named_attribute_value("qualifiers"); } if (parser->has_attribute("is_deprecated")) { - method.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true"; + method.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true"; } if (parser->has_attribute("is_experimental")) { - method.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true"; + method.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true"; } while (parser->read() == OK) { @@ -1037,21 +1038,21 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & String name = parser->get_node_name(); if (name == "return") { ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); - method.return_type = parser->get_attribute_value("type"); + method.return_type = parser->get_named_attribute_value("type"); if (parser->has_attribute("enum")) { - method.return_enum = parser->get_attribute_value("enum"); + method.return_enum = parser->get_named_attribute_value("enum"); } } else if (name == "returns_error") { ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT); - method.errors_returned.push_back(parser->get_attribute_value("number").to_int()); + method.errors_returned.push_back(parser->get_named_attribute_value("number").to_int()); } else if (name == "param") { DocData::ArgumentDoc argument; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); - argument.name = parser->get_attribute_value("name"); + argument.name = parser->get_named_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); - argument.type = parser->get_attribute_value("type"); + argument.type = parser->get_named_attribute_value("type"); if (parser->has_attribute("enum")) { - argument.enumeration = parser->get_attribute_value("enum"); + argument.enumeration = parser->get_named_attribute_value("enum"); } method.arguments.push_back(argument); @@ -1153,21 +1154,21 @@ Error DocTools::_load(Ref<XMLParser> parser) { ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT); ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); - String name = parser->get_attribute_value("name"); + String name = parser->get_named_attribute_value("name"); class_list[name] = DocData::ClassDoc(); DocData::ClassDoc &c = class_list[name]; c.name = name; if (parser->has_attribute("inherits")) { - c.inherits = parser->get_attribute_value("inherits"); + c.inherits = parser->get_named_attribute_value("inherits"); } if (parser->has_attribute("is_deprecated")) { - c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true"; + c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true"; } if (parser->has_attribute("is_experimental")) { - c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true"; + c.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true"; } while (parser->read() == OK) { @@ -1193,7 +1194,7 @@ Error DocTools::_load(Ref<XMLParser> parser) { if (name3 == "link") { DocData::TutorialDoc tutorial; if (parser->has_attribute("title")) { - tutorial.title = parser->get_attribute_value("title"); + tutorial.title = parser->get_named_attribute_value("title"); } parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) { @@ -1231,23 +1232,23 @@ Error DocTools::_load(Ref<XMLParser> parser) { DocData::PropertyDoc prop2; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); - prop2.name = parser->get_attribute_value("name"); + prop2.name = parser->get_named_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); - prop2.type = parser->get_attribute_value("type"); + prop2.type = parser->get_named_attribute_value("type"); if (parser->has_attribute("setter")) { - prop2.setter = parser->get_attribute_value("setter"); + prop2.setter = parser->get_named_attribute_value("setter"); } if (parser->has_attribute("getter")) { - prop2.getter = parser->get_attribute_value("getter"); + prop2.getter = parser->get_named_attribute_value("getter"); } if (parser->has_attribute("enum")) { - prop2.enumeration = parser->get_attribute_value("enum"); + prop2.enumeration = parser->get_named_attribute_value("enum"); } if (parser->has_attribute("is_deprecated")) { - prop2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true"; + prop2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true"; } if (parser->has_attribute("is_experimental")) { - prop2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true"; + prop2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true"; } if (!parser->is_empty()) { parser->read(); @@ -1274,11 +1275,11 @@ Error DocTools::_load(Ref<XMLParser> parser) { DocData::ThemeItemDoc prop2; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); - prop2.name = parser->get_attribute_value("name"); + prop2.name = parser->get_named_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); - prop2.type = parser->get_attribute_value("type"); + prop2.type = parser->get_named_attribute_value("type"); ERR_FAIL_COND_V(!parser->has_attribute("data_type"), ERR_FILE_CORRUPT); - prop2.data_type = parser->get_attribute_value("data_type"); + prop2.data_type = parser->get_named_attribute_value("data_type"); if (!parser->is_empty()) { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) { @@ -1303,21 +1304,21 @@ Error DocTools::_load(Ref<XMLParser> parser) { if (name3 == "constant") { DocData::ConstantDoc constant2; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); - constant2.name = parser->get_attribute_value("name"); + constant2.name = parser->get_named_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT); - constant2.value = parser->get_attribute_value("value"); + constant2.value = parser->get_named_attribute_value("value"); constant2.is_value_valid = true; if (parser->has_attribute("enum")) { - constant2.enumeration = parser->get_attribute_value("enum"); + constant2.enumeration = parser->get_named_attribute_value("enum"); } if (parser->has_attribute("is_bitfield")) { - constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true"; + constant2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true"; } if (parser->has_attribute("is_deprecated")) { - constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true"; + constant2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true"; } if (parser->has_attribute("is_experimental")) { - constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true"; + constant2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true"; } if (!parser->is_empty()) { parser->read(); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 5c97dc2d03..f4cefc606b 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -765,10 +765,6 @@ void EditorAudioBus::_bind_methods() { ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus); ClassDB::bind_method("update_send", &EditorAudioBus::update_send); - ClassDB::bind_method("_get_drag_data_fw", &EditorAudioBus::get_drag_data_fw); - ClassDB::bind_method("_can_drop_data_fw", &EditorAudioBus::can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &EditorAudioBus::drop_data_fw); - ADD_SIGNAL(MethodInfo("duplicate_request")); ADD_SIGNAL(MethodInfo("delete_request")); ADD_SIGNAL(MethodInfo("vol_reset_request")); @@ -903,7 +899,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited)); effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected)); effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); - effects->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus); effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb)); effects->set_allow_rmb_select(true); effects->set_focus_mode(FOCUS_CLICK); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 65e3e5c0d8..f843733f2c 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -808,12 +808,6 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) { } void EditorAutoloadSettings::_bind_methods() { - ClassDB::bind_method("_autoload_open", &EditorAutoloadSettings::_autoload_open); - - ClassDB::bind_method("_get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw); - ClassDB::bind_method("_can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &EditorAutoloadSettings::drop_data_fw); - ClassDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload); ClassDB::bind_method("autoload_add", &EditorAutoloadSettings::autoload_add); ClassDB::bind_method("autoload_remove", &EditorAutoloadSettings::autoload_remove); @@ -935,7 +929,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() { tree->set_select_mode(Tree::SELECT_MULTI); tree->set_allow_reselect(true); - tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(tree, EditorAutoloadSettings); tree->set_columns(4); tree->set_column_titles_visible(true); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 6e66962605..3059ce445c 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -122,12 +122,6 @@ int EditorSelectionHistory::get_history_pos() { return current_elem_idx; } -bool EditorSelectionHistory::is_history_obj_inspector_only(int p_obj) const { - ERR_FAIL_INDEX_V(p_obj, history.size(), false); - ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), false); - return history[p_obj].path[history[p_obj].level].inspector_only; -} - ObjectID EditorSelectionHistory::get_history_obj(int p_obj) const { ERR_FAIL_INDEX_V(p_obj, history.size(), ObjectID()); ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), ObjectID()); @@ -351,18 +345,6 @@ void EditorData::apply_changes_in_editors() { } } -void EditorData::save_editor_global_states() { - for (int i = 0; i < editor_plugins.size(); i++) { - editor_plugins[i]->save_global_state(); - } -} - -void EditorData::restore_editor_global_states() { - for (int i = 0; i < editor_plugins.size(); i++) { - editor_plugins[i]->restore_global_state(); - } -} - void EditorData::paste_object_params(Object *p_object) { ERR_FAIL_NULL(p_object); undo_redo_manager->create_action(TTR("Paste Params")); diff --git a/editor/editor_data.h b/editor/editor_data.h index 5ef42da3c9..d00501280d 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -80,7 +80,6 @@ public: // Gets an object from the history. The most recent object would be the object with p_obj = get_history_len() - 1. ObjectID get_history_obj(int p_obj) const; - bool is_history_obj_inspector_only(int p_obj) const; bool next(); bool previous(); @@ -177,7 +176,6 @@ public: Callable get_move_array_element_function(const StringName &p_class) const; void save_editor_global_states(); - void restore_editor_global_states(); void add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon); Variant instantiate_custom_type(const String &p_type, const String &p_inherits); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index a83a53ad15..33a1fe4b45 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -980,7 +980,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { no_profile_selected_help = memnew(Label(TTR("Create or import a profile to edit available classes and properties."))); // Add some spacing above the help label. Ref<StyleBoxEmpty> sb = memnew(StyleBoxEmpty); - sb->set_default_margin(SIDE_TOP, 20 * EDSCALE); + sb->set_content_margin(SIDE_TOP, 20 * EDSCALE); no_profile_selected_help->add_theme_style_override("normal", sb); no_profile_selected_help->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); no_profile_selected_help->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 9c056ffdd9..ef33b82390 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -47,7 +47,7 @@ EditorFileSystem *EditorFileSystem::singleton = nullptr; //the name is the version, to keep compatibility with different versions of Godot -#define CACHE_FILE_NAME "filesystem_cache7" +#define CACHE_FILE_NAME "filesystem_cache8" void EditorFileSystemDirectory::sort_files() { files.sort_custom<FileInfoSort>(); @@ -169,6 +169,11 @@ StringName EditorFileSystemDirectory::get_file_type(int p_idx) const { return files[p_idx]->type; } +StringName EditorFileSystemDirectory::get_file_resource_script_class(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, files.size(), ""); + return files[p_idx]->resource_script_class; +} + String EditorFileSystemDirectory::get_name() { return name; } @@ -266,6 +271,10 @@ void EditorFileSystem::_scan_filesystem() { FileCache fc; fc.type = split[1]; + if (fc.type.find("/") != -1) { + fc.type = fc.type.get_slice("/", 0); + fc.resource_script_class = fc.type.get_slice("/", 1); + } fc.uid = split[2].to_int(); fc.modification_time = split[3].to_int(); fc.import_modification_time = split[4].to_int(); @@ -602,10 +611,19 @@ bool EditorFileSystem::_update_scan_actions() { fs_changed = true; + if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) { + _queue_update_script_class(ia.dir->get_file_path(idx)); + } + } break; case ItemAction::ACTION_FILE_REMOVE: { int idx = ia.dir->find_file_index(ia.file); ERR_CONTINUE(idx == -1); + + if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) { + _queue_update_script_class(ia.dir->get_file_path(idx)); + } + _delete_internal_files(ia.dir->files[idx]->file); memdelete(ia.dir->files[idx]); ia.dir->files.remove_at(idx); @@ -640,6 +658,10 @@ bool EditorFileSystem::_update_scan_actions() { ERR_CONTINUE(idx == -1); String full_path = ia.dir->get_file_path(idx); + if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) { + _queue_update_script_class(full_path); + } + reloads.push_back(full_path); } break; @@ -708,9 +730,9 @@ void EditorFileSystem::scan() { new_filesystem = nullptr; _update_scan_actions(); scanning = false; + _update_pending_script_classes(); emit_signal(SNAME("filesystem_changed")); emit_signal(SNAME("sources_changed"), sources_changed.size() > 0); - _queue_update_script_classes(); first_scan = false; } else { ERR_FAIL_COND(thread.is_started()); @@ -841,6 +863,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc if (fc && fc->modification_time == mt && fc->import_modification_time == import_mt && !_test_for_reimport(path, true)) { fi->type = fc->type; + fi->resource_script_class = fc->resource_script_class; fi->uid = fc->uid; fi->deps = fc->deps; fi->modified_time = fc->modification_time; @@ -862,6 +885,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc if (fc->type.is_empty()) { fi->type = ResourceLoader::get_resource_type(path); + fi->resource_script_class = ResourceLoader::get_resource_script_class(path); fi->import_group_file = ResourceLoader::get_import_group_file(path); //there is also the chance that file type changed due to reimport, must probably check this somehow here (or kind of note it for next time in another file?) //note: I think this should not happen any longer.. @@ -891,6 +915,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc if (fc && fc->modification_time == mt) { //not imported, so just update type if changed fi->type = fc->type; + fi->resource_script_class = fc->resource_script_class; fi->uid = fc->uid; fi->modified_time = fc->modification_time; fi->deps = fc->deps; @@ -902,6 +927,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc } else { //new or modified time fi->type = ResourceLoader::get_resource_type(path); + fi->resource_script_class = ResourceLoader::get_resource_script_class(path); if (fi->type == "" && textfile_extensions.has(ext)) { fi->type = "TextFile"; } @@ -911,6 +937,10 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc fi->modified_time = mt; fi->import_modified_time = 0; fi->import_valid = true; + + if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) { + _queue_update_script_class(path); + } } } @@ -922,20 +952,6 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc } } - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptLanguage *lang = ScriptServer::get_language(i); - if (lang->supports_documentation() && fi->type == lang->get_type()) { - Ref<Script> scr = ResourceLoader::load(path); - if (scr == nullptr) { - continue; - } - Vector<DocData::ClassDoc> docs = scr->get_documentation(); - for (int j = 0; j < docs.size(); j++) { - EditorHelp::get_doc_data()->add_doc(docs[j]); - } - } - } - p_dir->files.push_back(fi); p_progress.update(idx, total); } @@ -1026,6 +1042,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const fi->modified_time = FileAccess::get_modified_time(path); fi->import_modified_time = 0; fi->type = ResourceLoader::get_resource_type(path); + fi->resource_script_class = ResourceLoader::get_resource_script_class(path); if (fi->type == "" && textfile_extensions.has(ext)) { fi->type = "TextFile"; } @@ -1176,7 +1193,9 @@ void EditorFileSystem::scan_changes() { sp.low = 0; scan_total = 0; _scan_fs_changes(filesystem, sp); - if (_update_scan_actions()) { + bool changed = _update_scan_actions(); + _update_pending_script_classes(); + if (changed) { emit_signal(SNAME("filesystem_changed")); } } @@ -1225,11 +1244,12 @@ void EditorFileSystem::_notification(int p_what) { set_process(false); thread_sources.wait_to_finish(); - if (_update_scan_actions()) { + bool changed = _update_scan_actions(); + _update_pending_script_classes(); + if (changed) { emit_signal(SNAME("filesystem_changed")); } emit_signal(SNAME("sources_changed"), sources_changed.size() > 0); - _queue_update_script_classes(); first_scan = false; } } else if (!scanning && thread.is_started()) { @@ -1242,9 +1262,9 @@ void EditorFileSystem::_notification(int p_what) { new_filesystem = nullptr; thread.wait_to_finish(); _update_scan_actions(); + _update_pending_script_classes(); emit_signal(SNAME("filesystem_changed")); emit_signal(SNAME("sources_changed"), sources_changed.size() > 0); - _queue_update_script_classes(); first_scan = false; } @@ -1279,7 +1299,12 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir, if (!p_dir->files[i]->import_group_file.is_empty()) { group_file_cache.insert(p_dir->files[i]->import_group_file); } - String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->uid) + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->import_group_file + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path; + + String type = p_dir->files[i]->type; + if (p_dir->files[i]->resource_script_class) { + type += "/" + String(p_dir->files[i]->resource_script_class); + } + String s = p_dir->files[i]->file + "::" + type + "::" + itos(p_dir->files[i]->uid) + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->import_group_file + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path; s += "::"; for (int j = 0; j < p_dir->files[i]->deps.size(); j++) { if (j > 0) { @@ -1491,40 +1516,65 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St return String(); } -void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) { - int filecount = p_dir->files.size(); - const EditorFileSystemDirectory::FileInfo *const *files = p_dir->files.ptr(); - for (int i = 0; i < filecount; i++) { - if (files[i]->script_class_name.is_empty()) { +void EditorFileSystem::_update_script_classes() { + update_script_mutex.lock(); + + for (const String &path : update_script_paths) { + ScriptServer::remove_global_class_by_path(path); // First remove, just in case it changed + + int index = -1; + EditorFileSystemDirectory *efd = find_file(path, &index); + + if (!efd || index < 0) { + // The file was removed continue; } - String lang; - for (int j = 0; j < ScriptServer::get_language_count(); j++) { - if (ScriptServer::get_language(j)->handles_global_class_type(files[i]->type)) { - lang = ScriptServer::get_language(j)->get_name(); + if (!efd->files[index]->script_class_name.is_empty()) { + String lang; + for (int j = 0; j < ScriptServer::get_language_count(); j++) { + if (ScriptServer::get_language(j)->handles_global_class_type(efd->files[index]->type)) { + lang = ScriptServer::get_language(j)->get_name(); + } + } + if (lang.is_empty()) { + continue; // No lang found that can handle this global class } + + ScriptServer::add_global_class(efd->files[index]->script_class_name, efd->files[index]->script_class_extends, lang, path); + EditorNode::get_editor_data().script_class_set_icon_path(efd->files[index]->script_class_name, efd->files[index]->script_class_icon_path); + EditorNode::get_editor_data().script_class_set_name(efd->files[index]->file, efd->files[index]->script_class_name); } - ScriptServer::add_global_class(files[i]->script_class_name, files[i]->script_class_extends, lang, p_dir->get_file_path(i)); - EditorNode::get_editor_data().script_class_set_icon_path(files[i]->script_class_name, files[i]->script_class_icon_path); - EditorNode::get_editor_data().script_class_set_name(files[i]->file, files[i]->script_class_name); - } - for (int i = 0; i < p_dir->get_subdir_count(); i++) { - _scan_script_classes(p_dir->get_subdir(i)); } -} -void EditorFileSystem::update_script_classes() { - if (!update_script_classes_queued.is_set()) { - return; - } + // Parse documentation second, as it requires the class names to be correct and registered + for (const String &path : update_script_paths) { + int index = -1; + EditorFileSystemDirectory *efd = find_file(path, &index); - update_script_classes_queued.clear(); - ScriptServer::global_classes_clear(); - if (get_filesystem()) { - _scan_script_classes(get_filesystem()); + if (!efd || index < 0) { + // The file was removed + continue; + } + + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptLanguage *lang = ScriptServer::get_language(i); + if (lang->supports_documentation() && efd->files[index]->type == lang->get_type()) { + Ref<Script> scr = ResourceLoader::load(path); + if (scr.is_null()) { + continue; + } + Vector<DocData::ClassDoc> docs = scr->get_documentation(); + for (int j = 0; j < docs.size(); j++) { + EditorHelp::get_doc_data()->add_doc(docs[j]); + } + } + } } + update_script_paths.clear(); + update_script_mutex.unlock(); + ScriptServer::save_global_classes(); EditorNode::get_editor_data().script_class_save_icon_paths(); emit_signal("script_classes_updated"); @@ -1538,13 +1588,16 @@ void EditorFileSystem::update_script_classes() { ResourceSaver::add_custom_savers(); } -void EditorFileSystem::_queue_update_script_classes() { - if (update_script_classes_queued.is_set()) { - return; +void EditorFileSystem::_update_pending_script_classes() { + if (!update_script_paths.is_empty()) { + _update_script_classes(); } +} - update_script_classes_queued.set(); - call_deferred(SNAME("update_script_classes")); +void EditorFileSystem::_queue_update_script_class(const String &p_path) { + update_script_mutex.lock(); + update_script_paths.insert(p_path); + update_script_mutex.unlock(); } void EditorFileSystem::update_file(const String &p_file) { @@ -1566,12 +1619,16 @@ void EditorFileSystem::update_file(const String &p_file) { ResourceUID::get_singleton()->remove_id(fs->files[cpos]->uid); } } + if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) { + _queue_update_script_class(p_file); + } + memdelete(fs->files[cpos]); fs->files.remove_at(cpos); } + _update_pending_script_classes(); call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later - _queue_update_script_classes(); return; } @@ -1579,6 +1636,8 @@ void EditorFileSystem::update_file(const String &p_file) { if (type.is_empty() && textfile_extensions.has(p_file.get_extension())) { type = "TextFile"; } + String script_class = ResourceLoader::get_resource_script_class(p_file); + ResourceUID::ID uid = ResourceLoader::get_resource_uid(p_file); if (cpos == -1) { @@ -1612,6 +1671,7 @@ void EditorFileSystem::update_file(const String &p_file) { } fs->files[cpos]->type = type; + fs->files[cpos]->resource_script_class = script_class; fs->files[cpos]->uid = uid; fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path); fs->files[cpos]->import_group_file = ResourceLoader::get_import_group_file(p_file); @@ -1631,8 +1691,12 @@ void EditorFileSystem::update_file(const String &p_file) { // Update preview EditorResourcePreview::get_singleton()->check_for_invalidation(p_file); + if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) { + _queue_update_script_class(p_file); + } + + _update_pending_script_classes(); call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later - _queue_update_script_classes(); } HashSet<String> EditorFileSystem::get_valid_extensions() const { @@ -2414,7 +2478,6 @@ void EditorFileSystem::_bind_methods() { ClassDB::bind_method(D_METHOD("update_file", "path"), &EditorFileSystem::update_file); ClassDB::bind_method(D_METHOD("get_filesystem_path", "path"), &EditorFileSystem::get_filesystem_path); ClassDB::bind_method(D_METHOD("get_file_type", "path"), &EditorFileSystem::get_file_type); - ClassDB::bind_method(D_METHOD("update_script_classes"), &EditorFileSystem::update_script_classes); ClassDB::bind_method(D_METHOD("reimport_files", "files"), &EditorFileSystem::reimport_files); ADD_SIGNAL(MethodInfo("filesystem_changed")); @@ -2474,7 +2537,6 @@ EditorFileSystem::EditorFileSystem() { using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT"); scan_total = 0; - update_script_classes_queued.clear(); MessageQueue::get_singleton()->push_callable(callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear)); // Will be updated on scan. ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path); } diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 2985134093..2490bd31b3 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -54,6 +54,7 @@ class EditorFileSystemDirectory : public Object { struct FileInfo { String file; StringName type; + StringName resource_script_class; // If any resource has script with a global class name, its found here. ResourceUID::ID uid = ResourceUID::INVALID_ID; uint64_t modified_time = 0; uint64_t import_modified_time = 0; @@ -61,6 +62,7 @@ class EditorFileSystemDirectory : public Object { String import_group_file; Vector<String> deps; bool verified = false; //used for checking changes + // These are for script resources only. String script_class_name; String script_class_extends; String script_class_icon_path; @@ -90,6 +92,7 @@ public: String get_file(int p_idx) const; String get_file_path(int p_idx) const; StringName get_file_type(int p_idx) const; + StringName get_file_resource_script_class(int p_idx) const; Vector<String> get_file_deps(int p_idx) const; bool get_file_import_is_valid(int p_idx) const; uint64_t get_file_modified_time(int p_idx) const; @@ -189,6 +192,7 @@ class EditorFileSystem : public Node { /* Used for reading the filesystem cache file */ struct FileCache { String type; + String resource_script_class; ResourceUID::ID uid = ResourceUID::INVALID_ID; uint64_t modification_time = 0; uint64_t import_modification_time = 0; @@ -257,9 +261,11 @@ class EditorFileSystem : public Node { } }; - void _scan_script_classes(EditorFileSystemDirectory *p_dir); - SafeFlag update_script_classes_queued; - void _queue_update_script_classes(); + Mutex update_script_mutex; + HashSet<String> update_script_paths; + void _queue_update_script_class(const String &p_path); + void _update_script_classes(); + void _update_pending_script_classes(); String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const; @@ -312,8 +318,6 @@ public: void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params); - void update_script_classes(); - bool is_group_file(const String &p_path) const; void move_group_file(const String &p_path, const String &p_new_path); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 9b1a5e028b..4cf947b006 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -195,8 +195,8 @@ void EditorHelp::_class_desc_resized(bool p_force_update_theme) { display_margin = new_display_margin; Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox(SNAME("background"), SNAME("EditorHelp"))->duplicate(); - class_desc_stylebox->set_default_margin(SIDE_LEFT, display_margin); - class_desc_stylebox->set_default_margin(SIDE_RIGHT, display_margin); + class_desc_stylebox->set_content_margin(SIDE_LEFT, display_margin); + class_desc_stylebox->set_content_margin(SIDE_RIGHT, display_margin); class_desc->add_theme_style_override("normal", class_desc_stylebox); class_desc->add_theme_style_override("focused", class_desc_stylebox); } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 5c977de8ff..4753761f05 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2049,7 +2049,7 @@ void EditorInspectorArray::_setup() { ae.panel = memnew(PanelContainer); ae.panel->set_focus_mode(FOCUS_ALL); ae.panel->set_mouse_filter(MOUSE_FILTER_PASS); - ae.panel->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(ae.panel, EditorInspectorArray); ae.panel->set_meta("index", begin_array_index + i); ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i)); ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw)); @@ -2181,8 +2181,7 @@ void EditorInspectorArray::_notification(int p_what) { odd_style->set_bg_color(color.darkened(-0.08)); even_style->set_bg_color(color.darkened(0.08)); - for (int i = 0; i < (int)array_elements.size(); i++) { - ArrayElement &ae = array_elements[i]; + for (ArrayElement &ae : array_elements) { if (ae.move_texture_rect) { ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons"))); } @@ -2220,10 +2219,6 @@ void EditorInspectorArray::_notification(int p_what) { } void EditorInspectorArray::_bind_methods() { - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorInspectorArray::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorInspectorArray::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorInspectorArray::drop_data_fw); - ADD_SIGNAL(MethodInfo("page_change_request")); } @@ -3287,6 +3282,11 @@ void EditorInspector::update_tree() { ped->parse_end(object); _parse_added_editors(main_vbox, nullptr, ped); } + + if (_is_main_editor_inspector()) { + // Updating inspector might invalidate some editing owners. + EditorNode::get_singleton()->hide_unused_editors(); + } } void EditorInspector::update_property(const String &p_prop) { @@ -3311,6 +3311,9 @@ void EditorInspector::_clear() { sections.clear(); pending.clear(); restart_request_props.clear(); + if (_is_main_editor_inspector()) { + EditorNode::get_singleton()->hide_unused_editors(this); + } } Object *EditorInspector::get_edited_object() { @@ -3645,6 +3648,10 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo } } +bool EditorInspector::_is_main_editor_inspector() const { + return InspectorDock::get_singleton() && InspectorDock::get_inspector_singleton() == this; +} + void EditorInspector::_property_changed(const String &p_path, const Variant &p_value, const String &p_name, bool p_changing, bool p_update_all) { // The "changing" variable must be true for properties that trigger events as typing occurs, // like "text_changed" signal. E.g. text property of Label, Button, RichTextLabel, etc. diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 699a88e657..1690302e6e 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -502,6 +502,7 @@ class EditorInspector : public ScrollContainer { bool restrict_to_basic = false; void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field); + bool _is_main_editor_inspector() const; void _property_changed(const String &p_path, const Variant &p_value, const String &p_name = "", bool p_changing = false, bool p_update_all = false); void _multiple_properties_changed(Vector<String> p_paths, Array p_values, bool p_changing = false); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2728365823..c344812065 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2080,51 +2080,56 @@ bool EditorNode::_is_class_editor_disabled_by_feature_profile(const StringName & return false; } -void EditorNode::edit_item(Object *p_object) { +void EditorNode::edit_item(Object *p_object, Object *p_editing_owner) { + ERR_FAIL_NULL(p_editing_owner); + if (p_object && _is_class_editor_disabled_by_feature_profile(p_object->get_class())) { return; } - Vector<EditorPlugin *> top_plugins = editor_plugins_over->get_plugins_list(); Vector<EditorPlugin *> item_plugins; if (p_object) { item_plugins = editor_data.get_subeditors(p_object); } if (!item_plugins.is_empty()) { - bool same = true; - if (item_plugins.size() == top_plugins.size()) { - for (int i = 0; i < item_plugins.size(); i++) { - if (item_plugins[i] != top_plugins[i]) { - same = false; - } + ObjectID owner_id = p_editing_owner->get_instance_id(); + + for (EditorPlugin *plugin : active_plugins[owner_id]) { + if (!item_plugins.has(plugin)) { + plugin->make_visible(false); + plugin->edit(nullptr); } - } else { - same = false; } - if (!same) { - _display_top_editors(false); - _set_top_editors(item_plugins); + for (EditorPlugin *plugin : item_plugins) { + for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) { + if (kv.key != owner_id) { + EditorPropertyResource *epres = Object::cast_to<EditorPropertyResource>(ObjectDB::get_instance(kv.key)); + if (epres && kv.value.has(plugin)) { + // If it's resource property editing the same resource type, fold it. + epres->fold_resource(); + } + kv.value.erase(plugin); + } + } + active_plugins[owner_id].insert(plugin); + editor_plugins_over->add_plugin(plugin); + plugin->edit(p_object); + plugin->make_visible(true); } - _set_editing_top_editors(p_object); - _display_top_editors(true); - } else if (!top_plugins.is_empty()) { - hide_top_editors(); + } else { + hide_unused_editors(p_editing_owner); } } -void EditorNode::edit_item_resource(Ref<Resource> p_resource) { - edit_item(p_resource.ptr()); -} - void EditorNode::push_item(Object *p_object, const String &p_property, bool p_inspector_only) { if (!p_object) { InspectorDock::get_inspector_singleton()->edit(nullptr); NodeDock::get_singleton()->set_node(nullptr); SceneTreeDock::get_singleton()->set_selected(nullptr); InspectorDock::get_singleton()->update(nullptr); - _display_top_editors(false); + hide_unused_editors(); return; } @@ -2152,22 +2157,34 @@ void EditorNode::_save_default_environment() { } } -void EditorNode::hide_top_editors() { - _display_top_editors(false); - - editor_plugins_over->clear(); -} - -void EditorNode::_display_top_editors(bool p_display) { - editor_plugins_over->make_visible(p_display); -} - -void EditorNode::_set_top_editors(Vector<EditorPlugin *> p_editor_plugins_over) { - editor_plugins_over->set_plugins_list(p_editor_plugins_over); -} +void EditorNode::hide_unused_editors(const Object *p_editing_owner) { + if (p_editing_owner) { + const ObjectID id = p_editing_owner->get_instance_id(); + for (EditorPlugin *plugin : active_plugins[id]) { + plugin->make_visible(false); + plugin->edit(nullptr); + editor_plugins_over->remove_plugin(plugin); + } + active_plugins.erase(id); + } else { + // If no editing owner is provided, this method will go over all owners and check if they are valid. + // This is to sweep properties that were removed from the inspector. + List<ObjectID> to_remove; + for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) { + if (!ObjectDB::get_instance(kv.key)) { + to_remove.push_back(kv.key); + for (EditorPlugin *plugin : kv.value) { + plugin->make_visible(false); + plugin->edit(nullptr); + editor_plugins_over->remove_plugin(plugin); + } + } + } -void EditorNode::_set_editing_top_editors(Object *p_current_object) { - editor_plugins_over->edit(p_current_object); + for (const ObjectID &id : to_remove) { + active_plugins.erase(id); + } + } } static bool overrides_external_editor(Object *p_object) { @@ -2201,7 +2218,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) { NodeDock::get_singleton()->set_node(nullptr); InspectorDock::get_singleton()->update(nullptr); - _display_top_editors(false); + hide_unused_editors(); return; } @@ -2329,6 +2346,9 @@ void EditorNode::_edit_current(bool p_skip_foreign) { InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding); } + Object *editor_owner = is_node ? (Object *)SceneTreeDock::get_singleton() : is_resource ? (Object *)InspectorDock::get_inspector_singleton() + : (Object *)this; + // Take care of the main editor plugin. if (!inspector_only) { @@ -2345,6 +2365,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) { } } + ObjectID editor_owner_id = editor_owner->get_instance_id(); if (main_plugin && !skip_main_plugin) { // Special case if use of external editor is true. Resource *current_res = Object::cast_to<Resource>(current_obj); @@ -2355,15 +2376,22 @@ void EditorNode::_edit_current(bool p_skip_foreign) { } else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) { + // Unedit previous plugin. + editor_plugin_screen->edit(nullptr); + active_plugins[editor_owner_id].erase(editor_plugin_screen); // Update screen main_plugin. editor_select(plugin_index); main_plugin->edit(current_obj); } else { editor_plugin_screen->edit(current_obj); } + is_main_screen_editing = true; + } else if (!main_plugin && editor_plugin_screen && is_main_screen_editing) { + editor_plugin_screen->edit(nullptr); + is_main_screen_editing = false; } - edit_item(current_obj); + edit_item(current_obj, editor_owner); } InspectorDock::get_singleton()->update(current_obj); @@ -3628,12 +3656,12 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { if (get_edited_scene()) { if (current_tab < 2) { - // Use heuristic instead. - int n2d = 0, n3d = 0; - _find_node_types(get_edited_scene(), n2d, n3d); - if (n2d > n3d) { + Node *editor_node = SceneTreeDock::get_singleton()->get_tree_editor()->get_selected(); + editor_node = editor_node == nullptr ? get_edited_scene() : editor_node; + + if (Object::cast_to<Node2D>(editor_node) || Object::cast_to<Control>(editor_node)) { editor_select(EDITOR_2D); - } else if (n3d > n2d) { + } else if (Object::cast_to<Node3D>(editor_node)) { editor_select(EDITOR_3D); } } @@ -3714,11 +3742,12 @@ void EditorNode::set_current_scene(int p_idx) { call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. } -void EditorNode::setup_color_picker(ColorPicker *picker) { +void EditorNode::setup_color_picker(ColorPicker *p_picker) { + p_picker->set_editor_settings(EditorSettings::get_singleton()); int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); - picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode); - picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); + p_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode); + p_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); } bool EditorNode::is_scene_open(const String &p_path) { @@ -7392,7 +7421,7 @@ EditorNode::EditorNode() { _reset_play_buttons(); - ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::META | KeyModifierMask::SHIFT | Key::F5); + ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5); ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R); play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene")); @@ -7544,8 +7573,8 @@ EditorNode::EditorNode() { right_r_vsplit->hide(); // Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize. - left_r_hsplit->set_split_offset(70 * EDSCALE); - main_hsplit->set_split_offset(-70 * EDSCALE); + left_r_hsplit->set_split_offset(270 * EDSCALE); + main_hsplit->set_split_offset(-270 * EDSCALE); // Define corresponding default layout. @@ -7560,8 +7589,8 @@ EditorNode::EditorNode() { default_layout->set_value(docks_section, "dock_split_" + itos(i + 1), 0); } default_layout->set_value(docks_section, "dock_hsplit_1", 0); - default_layout->set_value(docks_section, "dock_hsplit_2", 70 * EDSCALE); - default_layout->set_value(docks_section, "dock_hsplit_3", -70 * EDSCALE); + default_layout->set_value(docks_section, "dock_hsplit_2", 270 * EDSCALE); + default_layout->set_value(docks_section, "dock_hsplit_3", -270 * EDSCALE); default_layout->set_value(docks_section, "dock_hsplit_4", 0); _update_layouts_menu(); @@ -7876,7 +7905,6 @@ EditorNode::EditorNode() { _update_recent_scenes(); - editor_data.restore_editor_global_states(); set_process_shortcut_input(true); load_errors = memnew(RichTextLabel); diff --git a/editor/editor_node.h b/editor/editor_node.h index 163a056c8c..bb10abb589 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -68,6 +68,7 @@ class EditorLayoutsDialog; class EditorLog; class EditorPluginList; class EditorQuickOpen; +class EditorPropertyResource; class EditorResourcePreview; class EditorResourceConversionPlugin; class EditorRun; @@ -294,6 +295,8 @@ private: bool _initializing_plugins = false; HashMap<String, EditorPlugin *> addon_name_to_plugin; LocalVector<String> pending_addons; + HashMap<ObjectID, HashSet<EditorPlugin *>> active_plugins; + bool is_main_screen_editing = false; PanelContainer *scene_root_parent = nullptr; Control *theme_base = nullptr; @@ -593,10 +596,6 @@ private: void _inherit_request(String p_file); void _instantiate_request(const Vector<String> &p_files); - void _display_top_editors(bool p_display); - void _set_top_editors(Vector<EditorPlugin *> p_editor_plugins_over); - void _set_editing_top_editors(Object *p_current_object); - void _quick_opened(); void _quick_run(); void _open_command_palette(); @@ -797,9 +796,8 @@ public: void show_about() { _menu_option_confirm(HELP_ABOUT, false); } void push_item(Object *p_object, const String &p_property = "", bool p_inspector_only = false); - void edit_item(Object *p_object); - void edit_item_resource(Ref<Resource> p_resource); - void hide_top_editors(); + void edit_item(Object *p_object, Object *p_editing_owner); + void hide_unused_editors(const Object *p_editing_owner = nullptr); void select_editor_by_name(const String &p_name); @@ -856,7 +854,7 @@ public: void set_current_scene(int p_idx); - void setup_color_picker(ColorPicker *picker); + void setup_color_picker(ColorPicker *p_picker); void request_instantiate_scene(const String &p_path); void request_instantiate_scenes(const Vector<String> &p_files); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index ec866ad999..14cdbc364e 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -45,6 +45,7 @@ #include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" +#include "editor/plugins/editor_resource_conversion_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/project_settings_editor.h" @@ -661,7 +662,7 @@ void EditorPlugin::make_visible(bool p_visible) { } void EditorPlugin::edit(Object *p_object) { - if (p_object->is_class("Resource")) { + if (Object::cast_to<Resource>(p_object)) { GDVIRTUAL_CALL(_edit, Ref<Resource>(Object::cast_to<Resource>(p_object))); } else { GDVIRTUAL_CALL(_edit, p_object); @@ -711,9 +712,6 @@ bool EditorPlugin::get_remove_list(List<Node *> *p_list) { return false; } -void EditorPlugin::restore_global_state() {} -void EditorPlugin::save_global_state() {} - void EditorPlugin::add_undo_redo_inspector_hook_callback(Callable p_callable) { EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(p_callable); } @@ -856,6 +854,14 @@ void EditorPlugin::remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plu EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_plugin); } +void EditorPlugin::add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) { + EditorNode::get_singleton()->add_resource_conversion_plugin(p_plugin); +} + +void EditorPlugin::remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) { + EditorNode::get_singleton()->remove_resource_conversion_plugin(p_plugin); +} + void EditorPlugin::_editor_project_settings_changed() { emit_signal(SNAME("project_settings_changed")); } @@ -911,6 +917,8 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_node_3d_gizmo_plugin", "plugin"), &EditorPlugin::remove_node_3d_gizmo_plugin); ClassDB::bind_method(D_METHOD("add_inspector_plugin", "plugin"), &EditorPlugin::add_inspector_plugin); ClassDB::bind_method(D_METHOD("remove_inspector_plugin", "plugin"), &EditorPlugin::remove_inspector_plugin); + ClassDB::bind_method(D_METHOD("add_resource_conversion_plugin", "plugin"), &EditorPlugin::add_resource_conversion_plugin); + ClassDB::bind_method(D_METHOD("remove_resource_conversion_plugin", "plugin"), &EditorPlugin::remove_resource_conversion_plugin); ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled); ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 21eb4b89ef..a5a17acdf1 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -48,6 +48,7 @@ class EditorInspector; class EditorInspectorPlugin; class EditorNode3DGizmoPlugin; class EditorPaths; +class EditorResourceConversionPlugin; class EditorResourcePreview; class EditorSceneFormatImporter; class EditorScenePostImportPlugin; @@ -277,9 +278,6 @@ public: void make_bottom_panel_item_visible(Control *p_item); void hide_bottom_panel(); - virtual void restore_global_state(); - virtual void save_global_state(); - void add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser); void remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser); @@ -307,6 +305,9 @@ public: void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin); void remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin); + void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin); + void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin); + void enable_plugin(); void disable_plugin(); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index f528053fee..152e77acb7 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -268,7 +268,7 @@ void EditorPropertyTextEnum::_custom_value_accepted() { _custom_value_submitted(new_value); } -void EditorPropertyTextEnum::_custom_value_cancelled() { +void EditorPropertyTextEnum::_custom_value_canceled() { custom_value_edit->set_text(get_edited_object()->get(get_edited_property())); edit_custom_layout->hide(); @@ -342,12 +342,17 @@ void EditorPropertyTextEnum::_notification(int p_what) { } EditorPropertyTextEnum::EditorPropertyTextEnum() { + HBoxContainer *hb = memnew(HBoxContainer); + add_child(hb); + default_layout = memnew(HBoxContainer); - add_child(default_layout); + default_layout->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(default_layout); edit_custom_layout = memnew(HBoxContainer); + edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL); edit_custom_layout->hide(); - add_child(edit_custom_layout); + hb->add_child(edit_custom_layout); option_button = memnew(OptionButton); option_button->set_h_size_flags(SIZE_EXPAND_FILL); @@ -375,7 +380,7 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() { cancel_button = memnew(Button); cancel_button->set_flat(true); edit_custom_layout->add_child(cancel_button); - cancel_button->connect("pressed", callable_mp(this, &EditorPropertyTextEnum::_custom_value_cancelled)); + cancel_button->connect("pressed", callable_mp(this, &EditorPropertyTextEnum::_custom_value_canceled)); add_focusable(option_button); add_focusable(edit_button); @@ -561,15 +566,13 @@ bool EditorPropertyPath::_can_drop_data_fw(const Point2 &p_point, const Variant } void EditorPropertyPath::_bind_methods() { - ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_drop_data_fw); } EditorPropertyPath::EditorPropertyPath() { HBoxContainer *path_hb = memnew(HBoxContainer); add_child(path_hb); path = memnew(LineEdit); - path->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CDU(path, EditorPropertyPath); path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); path_hb->add_child(path); path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected)); @@ -3673,8 +3676,6 @@ void EditorPropertyNodePath::_notification(int p_what) { } void EditorPropertyNodePath::_bind_methods() { - ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyNodePath::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyNodePath::drop_data_fw); } EditorPropertyNodePath::EditorPropertyNodePath() { @@ -3686,7 +3687,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() { assign->set_h_size_flags(SIZE_EXPAND_FILL); assign->set_clip_text(true); assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign)); - assign->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath); hbc->add_child(assign); clear = memnew(Button); @@ -3904,40 +3905,7 @@ void EditorPropertyResource::_open_editor_pressed() { Ref<Resource> res = get_edited_object()->get(get_edited_property()); if (res.is_valid()) { // May clear the editor so do it deferred. - callable_mp(EditorNode::get_singleton(), &EditorNode::edit_item_resource).bind(res).call_deferred(); - } -} - -void EditorPropertyResource::_fold_other_editors(Object *p_self) { - if (this == p_self) { - return; - } - - Ref<Resource> res = get_edited_object()->get(get_edited_property()); - if (!res.is_valid()) { - return; - } - - bool use_editor = false; - for (int i = 0; i < EditorNode::get_editor_data().get_editor_plugin_count(); i++) { - EditorPlugin *ep = EditorNode::get_editor_data().get_editor_plugin(i); - if (ep->handles(res.ptr())) { - use_editor = true; - break; - } - } - if (!use_editor) { - return; - } - - opened_editor = false; - - bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); - if (unfolded) { - // Refold. - resource_picker->set_toggle_pressed(false); - get_edited_object()->editor_set_section_unfold(get_edited_property(), false); - update_property(); + callable_mp(EditorNode::get_singleton(), &EditorNode::edit_item).bind(res.ptr(), this).call_deferred(); } } @@ -4090,20 +4058,17 @@ void EditorPropertyResource::update_property() { sub_inspector_vbox->add_child(sub_inspector); resource_picker->set_toggle_pressed(true); - bool use_editor = false; + Array editor_list; for (int i = 0; i < EditorNode::get_editor_data().get_editor_plugin_count(); i++) { EditorPlugin *ep = EditorNode::get_editor_data().get_editor_plugin(i); if (ep->handles(res.ptr())) { - use_editor = true; + editor_list.push_back(ep); } } - if (use_editor) { - // Open editor directly and hide other such editors which are currently open. + if (!editor_list.is_empty()) { + // Open editor directly. _open_editor_pressed(); - if (is_inside_tree()) { - get_tree()->call_deferred(SNAME("call_group"), "_editor_resource_properties", "_fold_other_editors", this); - } opened_editor = true; } @@ -4122,7 +4087,7 @@ void EditorPropertyResource::update_property() { sub_inspector_vbox = nullptr; if (opened_editor) { - EditorNode::get_singleton()->hide_top_editors(); + EditorNode::get_singleton()->hide_unused_editors(); opened_editor = false; } @@ -4156,6 +4121,15 @@ void EditorPropertyResource::set_use_sub_inspector(bool p_enable) { use_sub_inspector = p_enable; } +void EditorPropertyResource::fold_resource() { + bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); + if (unfolded) { + resource_picker->set_toggle_pressed(false); + get_edited_object()->editor_set_section_unfold(get_edited_property(), false); + update_property(); + } +} + void EditorPropertyResource::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: @@ -4167,14 +4141,8 @@ void EditorPropertyResource::_notification(int p_what) { } } -void EditorPropertyResource::_bind_methods() { - ClassDB::bind_method(D_METHOD("_fold_other_editors"), &EditorPropertyResource::_fold_other_editors); -} - EditorPropertyResource::EditorPropertyResource() { use_sub_inspector = bool(EDITOR_GET("interface/inspector/open_resources_in_current_inspector")); - - add_to_group("_editor_resource_properties"); } ////////////// DEFAULT PLUGIN ////////////////////// diff --git a/editor/editor_properties.h b/editor/editor_properties.h index a255af30ee..d29ec12f97 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -121,7 +121,7 @@ class EditorPropertyTextEnum : public EditorProperty { void _edit_custom_value(); void _custom_value_submitted(String p_value); void _custom_value_accepted(); - void _custom_value_cancelled(); + void _custom_value_canceled(); protected: virtual void _set_read_only(bool p_read_only) override; @@ -834,13 +834,11 @@ class EditorPropertyResource : public EditorProperty { void _sub_inspector_object_id_selected(int p_id); void _open_editor_pressed(); - void _fold_other_editors(Object *p_self); void _update_property_bg(); void _update_preferred_shader(); protected: virtual void _set_read_only(bool p_read_only) override; - static void _bind_methods(); void _notification(int p_what); public: @@ -852,6 +850,7 @@ public: void expand_revertable() override; void set_use_sub_inspector(bool p_enable); + void fold_resource(); EditorPropertyResource(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 069e80fc05..28c0b047d8 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -702,8 +702,6 @@ void EditorPropertyArray::_reorder_button_up() { } void EditorPropertyArray::_bind_methods() { - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorPropertyArray::drop_data_fw); } EditorPropertyArray::EditorPropertyArray() { @@ -715,7 +713,7 @@ EditorPropertyArray::EditorPropertyArray() { edit->set_clip_text(true); edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed)); edit->set_toggle_mode(true); - edit->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CD(edit, EditorPropertyArray); edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw)); add_child(edit); add_focusable(edit); diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp index d516610908..b90edb8f90 100644 --- a/editor/editor_quick_open.cpp +++ b/editor/editor_quick_open.cpp @@ -69,17 +69,9 @@ void EditorQuickOpen::_build_search_cache(EditorFileSystemDirectory *p_efsd) { for (int i = 0; i < p_efsd->get_file_count(); i++) { String file = p_efsd->get_file_path(i); String engine_type = p_efsd->get_file_type(i); - // TODO: Fix lack of caching for resource's script's global class name (if applicable). - String script_type; - if (_load_resources) { - Ref<Resource> res = ResourceLoader::load(file); - if (res.is_valid()) { - Ref<Script> scr = res->get_script(); - if (scr.is_valid()) { - script_type = scr->get_language()->get_global_class_name(file); - } - } - } + + String script_type = p_efsd->get_file_resource_script_class(i); + String actual_type = script_type.is_empty() ? engine_type : script_type; // Iterate all possible base types. for (String &parent_type : base_types) { diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h index 0503eec835..4b63a226c2 100644 --- a/editor/editor_quick_open.h +++ b/editor/editor_quick_open.h @@ -43,7 +43,6 @@ class EditorQuickOpen : public ConfirmationDialog { Tree *search_options = nullptr; String base_type; bool allow_multi_select = false; - bool _load_resources = false; // Prohibitively slow for now. Vector<String> files; OAHashMap<String, Ref<Texture2D>> icons; diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 81b2fff97a..86ffbccefd 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -42,12 +42,6 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" -HashMap<StringName, List<StringName>> EditorResourcePicker::allowed_types_cache; - -void EditorResourcePicker::clear_caches() { - allowed_types_cache.clear(); -} - void EditorResourcePicker::_update_resource() { String resource_path; if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) { @@ -103,7 +97,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const } if (p_preview.is_valid()) { - preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(SNAME("normal"))->get_default_margin(SIDE_LEFT) + get_theme_constant(SNAME("h_separation"), SNAME("Button"))); + preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(SNAME("normal"))->get_content_margin(SIDE_LEFT) + get_theme_constant(SNAME("h_separation"), SNAME("Button"))); // Resource-specific stretching. if (Ref<GradientTexture1D>(edited_resource).is_valid() || Ref<Gradient>(edited_resource).is_valid()) { @@ -464,7 +458,7 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) { if (!base_type.is_empty()) { int idx = 0; - HashSet<String> allowed_types; + HashSet<StringName> allowed_types; _get_allowed_types(false, &allowed_types); Vector<EditorData::CustomType> custom_resources; @@ -472,7 +466,7 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) { custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"]; } - for (const String &E : allowed_types) { + for (const StringName &E : allowed_types) { const String &t = E; bool is_custom_resource = false; @@ -561,53 +555,44 @@ String EditorResourcePicker::_get_resource_type(const Ref<Resource> &p_resource) return res_type; } -void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const { - Vector<String> allowed_types = base_type.split(","); - int size = allowed_types.size(); +static void _add_allowed_type(const StringName &p_type, HashSet<StringName> *p_vector) { + if (p_vector->has(p_type)) { + // Already added + return; + } - List<StringName> global_classes; - ScriptServer::get_global_class_list(&global_classes); + if (ClassDB::class_exists(p_type)) { + // Engine class, - for (int i = 0; i < size; i++) { - String base = allowed_types[i].strip_edges(); - if (!ClassDB::is_virtual(base)) { - p_vector->insert(base); + if (!ClassDB::is_virtual(p_type)) { + p_vector->insert(p_type); } - // If we hit a familiar base type, take all the data from cache. - if (allowed_types_cache.has(base)) { - List<StringName> allowed_subtypes = allowed_types_cache[base]; - for (const StringName &subtype_name : allowed_subtypes) { - if (!ClassDB::is_virtual(subtype_name)) { - p_vector->insert(subtype_name); - } - } - } else { - List<StringName> allowed_subtypes; + List<StringName> inheriters; + ClassDB::get_inheriters_from_class(p_type, &inheriters); + for (const StringName &S : inheriters) { + _add_allowed_type(S, p_vector); + } + } else { + // Script class. + p_vector->insert(p_type); + } - List<StringName> inheriters; - if (!ScriptServer::is_global_class(base)) { - ClassDB::get_inheriters_from_class(base, &inheriters); - } - for (const StringName &subtype_name : inheriters) { - if (!ClassDB::is_virtual(subtype_name)) { - p_vector->insert(subtype_name); - } - allowed_subtypes.push_back(subtype_name); - } + List<StringName> inheriters; + ScriptServer::get_inheriters_list(p_type, &inheriters); + for (const StringName &S : inheriters) { + _add_allowed_type(S, p_vector); + } +} - for (const StringName &subtype_name : global_classes) { - if (EditorNode::get_editor_data().script_class_is_parent(subtype_name, base)) { - if (!ClassDB::is_virtual(subtype_name)) { - p_vector->insert(subtype_name); - } - allowed_subtypes.push_back(subtype_name); - } - } +void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const { + Vector<String> allowed_types = base_type.split(","); + int size = allowed_types.size(); - // Store the subtypes of the base type in the cache for future use. - allowed_types_cache[base] = allowed_subtypes; - } + for (int i = 0; i < size; i++) { + String base = allowed_types[i].strip_edges(); + + _add_allowed_type(base, p_vector); if (p_with_convert) { if (base == "BaseMaterial3D") { @@ -619,14 +604,6 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin } } } - - if (EditorNode::get_editor_data().get_custom_types().has("Resource")) { - Vector<EditorData::CustomType> custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"]; - - for (int i = 0; i < custom_resources.size(); i++) { - p_vector->insert(custom_resources[i].name); - } - } } bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { @@ -654,7 +631,7 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { } } - HashSet<String> allowed_types; + HashSet<StringName> allowed_types; _get_allowed_types(true, &allowed_types); if (res.is_valid()) { @@ -673,9 +650,9 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { return false; } -bool EditorResourcePicker::_is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const { - for (const String &E : p_allowed_types) { - String at = E.strip_edges(); +bool EditorResourcePicker::_is_type_valid(const String p_type_name, HashSet<StringName> p_allowed_types) const { + for (const StringName &E : p_allowed_types) { + String at = E; if (p_type_name == at || ClassDB::is_parent_class(p_type_name, at) || EditorNode::get_editor_data().script_class_is_parent(p_type_name, at)) { return true; } @@ -721,15 +698,15 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ } if (dropped_resource.is_valid()) { - HashSet<String> allowed_types; + HashSet<StringName> allowed_types; _get_allowed_types(false, &allowed_types); String res_type = _get_resource_type(dropped_resource); // If the accepted dropped resource is from the extended list, it requires conversion. if (!_is_type_valid(res_type, allowed_types)) { - for (const String &E : allowed_types) { - String at = E.strip_edges(); + for (const StringName &E : allowed_types) { + String at = E; if (at == "BaseMaterial3D" && Ref<Texture2D>(dropped_resource).is_valid()) { // Use existing resource if possible and only replace its data. @@ -772,9 +749,6 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ void EditorResourcePicker::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_resource_preview"), &EditorResourcePicker::_update_resource_preview); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &EditorResourcePicker::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::drop_data_fw); ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &EditorResourcePicker::set_base_type); ClassDB::bind_method(D_METHOD("get_base_type"), &EditorResourcePicker::get_base_type); @@ -835,7 +809,7 @@ void EditorResourcePicker::set_base_type(const String &p_base_type) { // There is a possibility that the new base type is conflicting with the existing value. // Keep the value, but warn the user that there is a potential mistake. if (!base_type.is_empty() && edited_resource.is_valid()) { - HashSet<String> allowed_types; + HashSet<StringName> allowed_types; _get_allowed_types(true, &allowed_types); StringName custom_class; @@ -849,10 +823,6 @@ void EditorResourcePicker::set_base_type(const String &p_base_type) { String class_str = (custom_class == StringName() ? edited_resource->get_class() : vformat("%s (%s)", custom_class, edited_resource->get_class())); WARN_PRINT(vformat("Value mismatch between the new base type of this EditorResourcePicker, '%s', and the type of the value it already has, '%s'.", base_type, class_str)); } - } else { - // Call the method to build the cache immediately. - HashSet<String> allowed_types; - _get_allowed_types(false, &allowed_types); } } @@ -861,7 +831,7 @@ String EditorResourcePicker::get_base_type() const { } Vector<String> EditorResourcePicker::get_allowed_types() const { - HashSet<String> allowed_types; + HashSet<StringName> allowed_types; _get_allowed_types(false, &allowed_types); Vector<String> types; @@ -869,7 +839,7 @@ Vector<String> EditorResourcePicker::get_allowed_types() const { int i = 0; String *w = types.ptrw(); - for (const String &E : allowed_types) { + for (const StringName &E : allowed_types) { w[i] = E; i++; } @@ -885,7 +855,7 @@ void EditorResourcePicker::set_edited_resource(Ref<Resource> p_resource) { } if (!base_type.is_empty()) { - HashSet<String> allowed_types; + HashSet<StringName> allowed_types; _get_allowed_types(true, &allowed_types); StringName custom_class; @@ -950,7 +920,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) { assign_button->set_flat(true); assign_button->set_h_size_flags(SIZE_EXPAND_FILL); assign_button->set_clip_text(true); - assign_button->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(assign_button, EditorResourcePicker); add_child(assign_button); assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected)); assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw)); diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 8641cb6e84..a302e24957 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -42,8 +42,6 @@ class EditorQuickOpen; class EditorResourcePicker : public HBoxContainer { GDCLASS(EditorResourcePicker, HBoxContainer); - static HashMap<StringName, List<StringName>> allowed_types_cache; - String base_type; Ref<Resource> edited_resource; @@ -92,9 +90,9 @@ class EditorResourcePicker : public HBoxContainer { void _button_input(const Ref<InputEvent> &p_event); String _get_resource_type(const Ref<Resource> &p_resource) const; - void _get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const; + void _get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const; bool _is_drop_valid(const Dictionary &p_drag_data) const; - bool _is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const; + bool _is_type_valid(const String p_type_name, HashSet<StringName> p_allowed_types) const; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -118,8 +116,6 @@ protected: GDVIRTUAL1R(bool, _handle_menu_selected, int) public: - static void clear_caches(); - void set_base_type(const String &p_base_type); String get_base_type() const; Vector<String> get_allowed_types() const; diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 49723aa169..0628dc7116 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -44,7 +44,8 @@ void EditorRunNative::_notification(int p_what) { bool changed = EditorExport::get_singleton()->poll_export_platforms() || first; if (changed) { - remote_debug->get_popup()->clear(); + PopupMenu *popup = remote_debug->get_popup(); + popup->clear(); for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i); if (eep.is_null()) { @@ -52,15 +53,22 @@ void EditorRunNative::_notification(int p_what) { } int dc = MIN(eep->get_options_count(), 9000); if (dc > 0) { - remote_debug->get_popup()->add_icon_item(eep->get_run_icon(), eep->get_name(), -1); - remote_debug->get_popup()->set_item_disabled(-1, true); + popup->add_icon_item(eep->get_run_icon(), eep->get_name(), -1); + popup->set_item_disabled(-1, true); for (int j = 0; j < dc; j++) { - remote_debug->get_popup()->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * i + j); - remote_debug->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(j)); - remote_debug->get_popup()->set_item_indent(-1, 2); + popup->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * i + j); + popup->set_item_tooltip(-1, eep->get_option_tooltip(j)); + popup->set_item_indent(-1, 2); } } } + if (popup->get_item_count() == 0) { + remote_debug->set_disabled(true); + remote_debug->set_tooltip_text(TTR("No Remote Debug export presets configured.")); + } else { + remote_debug->set_disabled(false); + remote_debug->set_tooltip_text(TTR("Remote Debug")); + } first = false; } @@ -149,6 +157,7 @@ EditorRunNative::EditorRunNative() { remote_debug->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native)); remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons"))); remote_debug->set_tooltip_text(TTR("Remote Debug")); + remote_debug->set_disabled(true); add_child(remote_debug); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 8ca98e6f76..4879790b74 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -473,6 +473,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { /* Filesystem */ + // External Programs + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/raster_image_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/vector_image_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/audio_editor", "", "") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/external_programs/3d_model_editor", "", "") + // Directories EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/autoscan_project_path", "", "") const String fs_dir_default_project_path = OS::get_singleton()->has_environment("HOME") ? OS::get_singleton()->get_environment("HOME") : OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index f6054529f9..ad614b1769 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -694,10 +694,6 @@ void EditorSettingsDialog::_editor_restart_close() { void EditorSettingsDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts); ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed); - - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorSettingsDialog::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorSettingsDialog::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorSettingsDialog::drop_data_fw); } EditorSettingsDialog::EditorSettingsDialog() { @@ -793,7 +789,7 @@ EditorSettingsDialog::EditorSettingsDialog() { shortcuts->connect("item_activated", callable_mp(this, &EditorSettingsDialog::_shortcut_cell_double_clicked)); tab_shortcuts->add_child(shortcuts); - shortcuts->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(shortcuts, EditorSettingsDialog); // Adding event dialog shortcut_editor = memnew(InputEventConfigurationDialog); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 177266e366..54e14074d9 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -278,11 +278,11 @@ void EditorSpinSlider::_update_value_input_stylebox() { // higher margin to match the location where the text begins. // The margin values below were determined by empirical testing. if (is_layout_rtl()) { - stylebox->set_default_margin(SIDE_LEFT, 0); - stylebox->set_default_margin(SIDE_RIGHT, (!get_label().is_empty() ? 23 : 16) * EDSCALE); + stylebox->set_content_margin(SIDE_LEFT, 0); + stylebox->set_content_margin(SIDE_RIGHT, (!get_label().is_empty() ? 23 : 16) * EDSCALE); } else { - stylebox->set_default_margin(SIDE_LEFT, (!get_label().is_empty() ? 23 : 16) * EDSCALE); - stylebox->set_default_margin(SIDE_RIGHT, 0); + stylebox->set_content_margin(SIDE_LEFT, (!get_label().is_empty() ? 23 : 16) * EDSCALE); + stylebox->set_content_margin(SIDE_RIGHT, 0); } value_input->add_theme_style_override("normal", stylebox); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 7a880d2ab3..745acca04b 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -197,15 +197,15 @@ void EditorColorMap::create() { static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) { Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(p_texture); - style->set_margin_size_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE); - style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); + style->set_texture_margin_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE); + style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); style->set_draw_center(p_draw_center); return style; } static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty)); - style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); + style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); return style; } @@ -215,7 +215,7 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = // Adjust level of detail based on the corners' effective sizes. style->set_corner_detail(Math::ceil(0.8 * p_corner_width * EDSCALE)); style->set_corner_radius_all(p_corner_width * EDSCALE); - style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); + style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); // Work around issue about antialiased edges being blurrier (GH-35279). style->set_anti_aliased(false); return style; @@ -648,7 +648,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE; Ref<StyleBoxFlat> style_widget = style_default->duplicate(); - style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y); + style_widget->set_content_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y); style_widget->set_bg_color(dark_color_1); if (draw_extra_borders) { style_widget->set_border_width_all(Math::round(EDSCALE)); @@ -684,7 +684,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Style for windows, popups, etc.. Ref<StyleBoxFlat> style_popup = style_default->duplicate(); const int popup_margin_size = default_margin_size * EDSCALE * 3; - style_popup->set_default_margin_all(popup_margin_size); + style_popup->set_content_margin_all(popup_margin_size); style_popup->set_border_color(contrast_color_1); const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1); style_popup->set_shadow_color(shadow_color); @@ -722,12 +722,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_tab_base->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); // When using a border width greater than 0, visually line up the left of the selected tab with the underlying panel. - style_tab_base->set_expand_margin_size(SIDE_LEFT, -border_width); + style_tab_base->set_expand_margin(SIDE_LEFT, -border_width); - style_tab_base->set_default_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE); - style_tab_base->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE); - style_tab_base->set_default_margin(SIDE_BOTTOM, widget_default_margin.y); - style_tab_base->set_default_margin(SIDE_TOP, widget_default_margin.y); + style_tab_base->set_content_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE); + style_tab_base->set_content_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE); + style_tab_base->set_content_margin(SIDE_BOTTOM, widget_default_margin.y); + style_tab_base->set_content_margin(SIDE_TOP, widget_default_margin.y); Ref<StyleBoxFlat> style_tab_selected = style_tab_base->duplicate(); @@ -740,13 +740,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_tab_selected->set_corner_radius_all(0); Ref<StyleBoxFlat> style_tab_unselected = style_tab_base->duplicate(); - style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0); + style_tab_unselected->set_expand_margin(SIDE_BOTTOM, 0); style_tab_unselected->set_bg_color(dark_color_1); // Add some spacing between unselected tabs to make them easier to distinguish from each other style_tab_unselected->set_border_color(Color(0, 0, 0, 0)); Ref<StyleBoxFlat> style_tab_disabled = style_tab_base->duplicate(); - style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0); + style_tab_disabled->set_expand_margin(SIDE_BOTTOM, 0); style_tab_disabled->set_bg_color(disabled_bg_color); style_tab_disabled->set_border_color(disabled_bg_color); @@ -772,7 +772,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // CanvasItem Editor Ref<StyleBoxFlat> style_canvas_editor_info = make_flat_stylebox(Color(0.0, 0.0, 0.0, 0.2)); - style_canvas_editor_info->set_expand_margin_size_all(4 * EDSCALE); + style_canvas_editor_info->set_expand_margin_all(4 * EDSCALE); theme->set_stylebox("CanvasItemInfoOverlay", "EditorStyles", style_canvas_editor_info); // 2D and 3D contextual toolbar. @@ -787,7 +787,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Add an underline to the StyleBox, but prevent its minimum vertical size from changing. toolbar_stylebox->set_border_color(accent_color); toolbar_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); - toolbar_stylebox->set_default_margin(SIDE_BOTTOM, 0); + toolbar_stylebox->set_content_margin(SIDE_BOTTOM, 0); theme->set_stylebox("ContextualToolbar", "EditorStyles", toolbar_stylebox); // Script Editor @@ -808,11 +808,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_write_movie_button = style_widget_pressed->duplicate(); style_write_movie_button->set_bg_color(accent_color); style_write_movie_button->set_corner_radius_all(corner_radius * EDSCALE); - style_write_movie_button->set_default_margin(SIDE_TOP, 0); - style_write_movie_button->set_default_margin(SIDE_BOTTOM, 0); - style_write_movie_button->set_default_margin(SIDE_LEFT, 0); - style_write_movie_button->set_default_margin(SIDE_RIGHT, 0); - style_write_movie_button->set_expand_margin_size(SIDE_RIGHT, 2 * EDSCALE); + style_write_movie_button->set_content_margin(SIDE_TOP, 0); + style_write_movie_button->set_content_margin(SIDE_BOTTOM, 0); + style_write_movie_button->set_content_margin(SIDE_LEFT, 0); + style_write_movie_button->set_content_margin(SIDE_RIGHT, 0); + style_write_movie_button->set_expand_margin(SIDE_RIGHT, 2 * EDSCALE); theme->set_stylebox("MovieWriterButtonPressed", "EditorStyles", style_write_movie_button); theme->set_stylebox("normal", "MenuButton", style_menu); @@ -855,16 +855,16 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { color_inspector_action.a = 0.5; Ref<StyleBoxFlat> style_inspector_action = style_widget->duplicate(); style_inspector_action->set_bg_color(color_inspector_action); - style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); theme->set_stylebox("normal", "InspectorActionButton", style_inspector_action); style_inspector_action = style_widget_hover->duplicate(); - style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); theme->set_stylebox("hover", "InspectorActionButton", style_inspector_action); style_inspector_action = style_widget_pressed->duplicate(); - style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); theme->set_stylebox("pressed", "InspectorActionButton", style_inspector_action); style_inspector_action = style_widget_disabled->duplicate(); - style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); theme->set_stylebox("disabled", "InspectorActionButton", style_inspector_action); theme->set_constant("h_separation", "InspectorActionButton", ACTION_BUTTON_EXTRA_MARGIN); @@ -908,11 +908,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_option_button_pressed = style_widget_pressed->duplicate(); Ref<StyleBoxFlat> style_option_button_disabled = style_widget_disabled->duplicate(); - style_option_button_focus->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); - style_option_button_normal->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); - style_option_button_hover->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); - style_option_button_pressed->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); - style_option_button_disabled->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); + style_option_button_focus->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); + style_option_button_normal->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); + style_option_button_hover->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); + style_option_button_pressed->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); + style_option_button_disabled->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); theme->set_stylebox("focus", "OptionButton", style_option_button_focus); theme->set_stylebox("normal", "OptionButton", style_widget); @@ -978,7 +978,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Checkbox Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate(); - sb_checkbox->set_default_margin_all(default_margin_size * EDSCALE); + sb_checkbox->set_content_margin_all(default_margin_size * EDSCALE); theme->set_stylebox("normal", "CheckBox", sb_checkbox); theme->set_stylebox("pressed", "CheckBox", sb_checkbox); @@ -1018,7 +1018,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn // on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted, // and it looks weird. 1px solves this. - style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE); + style_popup_menu->set_content_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE); // Always display a border for PopupMenus so they can be distinguished from their background. style_popup_menu->set_border_width_all(EDSCALE); if (draw_extra_borders) { @@ -1078,7 +1078,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { sub_inspector_bg->set_bg_color(dark_color_1.lerp(si_base_color, 0.08)); sub_inspector_bg->set_border_width_all(2 * EDSCALE); sub_inspector_bg->set_border_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8)); - sub_inspector_bg->set_default_margin_all(4 * EDSCALE); + sub_inspector_bg->set_content_margin_all(4 * EDSCALE); sub_inspector_bg->set_corner_radius(CORNER_TOP_LEFT, 0); sub_inspector_bg->set_corner_radius(CORNER_TOP_RIGHT, 0); @@ -1318,7 +1318,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0); style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0); // Compensate for the border. - style_content_panel->set_default_margin_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE); + style_content_panel->set_content_margin_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE); theme->set_stylebox("panel", "TabContainer", style_content_panel); // Bottom panel. @@ -1339,15 +1339,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // This stylebox is used in 3d and 2d viewports (no borders). Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate(); - style_content_panel_vp->set_default_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2); + style_content_panel_vp->set_content_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2); theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp); // This stylebox is used by preview tabs in the Theme Editor. Ref<StyleBoxFlat> style_theme_preview_tab = style_tab_selected_odd->duplicate(); - style_theme_preview_tab->set_expand_margin_size(SIDE_BOTTOM, 5 * EDSCALE); + style_theme_preview_tab->set_expand_margin(SIDE_BOTTOM, 5 * EDSCALE); theme->set_stylebox("ThemeEditorPreviewFG", "EditorStyles", style_theme_preview_tab); Ref<StyleBoxFlat> style_theme_preview_bg_tab = style_tab_unselected->duplicate(); - style_theme_preview_bg_tab->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE); + style_theme_preview_bg_tab->set_expand_margin(SIDE_BOTTOM, 2 * EDSCALE); theme->set_stylebox("ThemeEditorPreviewBG", "EditorStyles", style_theme_preview_bg_tab); // Separators @@ -1361,9 +1361,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("DebuggerPanel", "EditorStyles", style_panel_debugger); Ref<StyleBoxFlat> style_panel_invisible_top = style_content_panel->duplicate(); - int stylebox_offset = theme->get_font(SNAME("tab_selected"), SNAME("TabContainer"))->get_height(theme->get_font_size(SNAME("tab_selected"), SNAME("TabContainer"))) + theme->get_stylebox(SNAME("tab_selected"), SNAME("TabContainer"))->get_minimum_size().height + theme->get_stylebox(SNAME("panel"), SNAME("TabContainer"))->get_default_margin(SIDE_TOP); - style_panel_invisible_top->set_expand_margin_size(SIDE_TOP, -stylebox_offset); - style_panel_invisible_top->set_default_margin(SIDE_TOP, 0); + int stylebox_offset = theme->get_font(SNAME("tab_selected"), SNAME("TabContainer"))->get_height(theme->get_font_size(SNAME("tab_selected"), SNAME("TabContainer"))) + theme->get_stylebox(SNAME("tab_selected"), SNAME("TabContainer"))->get_minimum_size().height + theme->get_stylebox(SNAME("panel"), SNAME("TabContainer"))->get_content_margin(SIDE_TOP); + style_panel_invisible_top->set_expand_margin(SIDE_TOP, -stylebox_offset); + style_panel_invisible_top->set_content_margin(SIDE_TOP, 0); theme->set_stylebox("BottomPanelDebuggerOverride", "EditorStyles", style_panel_invisible_top); // LineEdit @@ -1371,7 +1371,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_line_edit = style_widget->duplicate(); // The original style_widget style has an extra 1 pixel offset that makes LineEdits not align with Buttons, // so this compensates for that. - style_line_edit->set_default_margin(SIDE_TOP, style_line_edit->get_default_margin(SIDE_TOP) - 1 * EDSCALE); + style_line_edit->set_content_margin(SIDE_TOP, style_line_edit->get_content_margin(SIDE_TOP) - 1 * EDSCALE); // Don't round the bottom corner to make the line look sharper. style_tab_selected->set_corner_radius(CORNER_BOTTOM_LEFT, 0); @@ -1459,12 +1459,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_window_title->set_corner_radius(CORNER_TOP_LEFT, 0); style_window_title->set_corner_radius(CORNER_TOP_RIGHT, 0); // Prevent visible line between window title and body. - style_window_title->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE); + style_window_title->set_expand_margin(SIDE_BOTTOM, 2 * EDSCALE); Ref<StyleBoxFlat> style_window = style_popup->duplicate(); style_window->set_border_color(base_color); style_window->set_border_width(SIDE_TOP, 24 * EDSCALE); - style_window->set_expand_margin_size(SIDE_TOP, 24 * EDSCALE); + style_window->set_expand_margin(SIDE_TOP, 24 * EDSCALE); theme->set_stylebox("embedded_border", "Window", style_window); theme->set_color("title_color", "Window", font_color); @@ -1598,7 +1598,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // is only relevant for default tooltips. Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate(); style_tooltip->set_shadow_size(0); - style_tooltip->set_default_margin_all(default_margin_size * EDSCALE * 0.5); + style_tooltip->set_content_margin_all(default_margin_size * EDSCALE * 0.5); style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9)); style_tooltip->set_border_width_all(0); theme->set_color("font_color", "TooltipLabel", font_hover_color); @@ -1610,10 +1610,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> control_editor_popup_style = style_popup->duplicate(); control_editor_popup_style->set_shadow_size(0); - control_editor_popup_style->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE); - control_editor_popup_style->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); - control_editor_popup_style->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE); - control_editor_popup_style->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE); + control_editor_popup_style->set_content_margin(SIDE_LEFT, default_margin_size * EDSCALE); + control_editor_popup_style->set_content_margin(SIDE_TOP, default_margin_size * EDSCALE); + control_editor_popup_style->set_content_margin(SIDE_RIGHT, default_margin_size * EDSCALE); + control_editor_popup_style->set_content_margin(SIDE_BOTTOM, default_margin_size * EDSCALE); control_editor_popup_style->set_border_width_all(0); theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style); @@ -1826,8 +1826,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Dictionary editor add item. // Expand to the left and right by 4px to compensate for the dictionary editor margins. Ref<StyleBoxFlat> style_dictionary_add_item = make_flat_stylebox(prop_subsection_color, 0, 4, 0, 4, corner_radius); - style_dictionary_add_item->set_expand_margin_size(SIDE_LEFT, 4 * EDSCALE); - style_dictionary_add_item->set_expand_margin_size(SIDE_RIGHT, 4 * EDSCALE); + style_dictionary_add_item->set_expand_margin(SIDE_LEFT, 4 * EDSCALE); + style_dictionary_add_item->set_expand_margin(SIDE_RIGHT, 4 * EDSCALE); theme->set_stylebox("DictionaryAddItem", "EditorStyles", style_dictionary_add_item); Ref<StyleBoxEmpty> vshader_label_style = make_empty_stylebox(2, 1, 2, 1); diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp index dd5d68a08e..73b645f351 100644 --- a/editor/editor_toaster.cpp +++ b/editor/editor_toaster.cpp @@ -90,11 +90,12 @@ void EditorToaster::_notification(int p_what) { } // Hide element if it is not visible anymore. - if (modulate_fade.a <= 0) { - if (element.key->is_visible()) { - element.key->hide(); - needs_update = true; - } + if (modulate_fade.a <= 0 && element.key->is_visible()) { + element.key->hide(); + needs_update = true; + } else if (modulate_fade.a >= 0 && !element.key->is_visible()) { + element.key->show(); + needs_update = true; } } @@ -229,10 +230,10 @@ void EditorToaster::_auto_hide_or_free_toasts() { } // Delete the control right away (removed as child) as it might cause issues otherwise when iterative over the vbox_container children. - for (unsigned int i = 0; i < to_delete.size(); i++) { - vbox_container->remove_child(to_delete[i]); - to_delete[i]->queue_free(); - toasts.erase(to_delete[i]); + for (Control *c : to_delete) { + vbox_container->remove_child(c); + c->queue_free(); + toasts.erase(c); } if (toasts.is_empty()) { @@ -419,12 +420,21 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t // Create a new message if needed. if (control == nullptr) { + HBoxContainer *hb = memnew(HBoxContainer); + hb->add_theme_constant_override("separation", 0); + Label *label = memnew(Label); + hb->add_child(label); - control = popup(label, p_severity, default_message_duration, p_tooltip); + Label *count_label = memnew(Label); + hb->add_child(count_label); + + control = popup(hb, p_severity, default_message_duration, p_tooltip); toasts[control].message = p_message; toasts[control].tooltip = p_tooltip; toasts[control].count = 1; + toasts[control].message_label = label; + toasts[control].message_count_label = count_label; } else { if (toasts[control].popped) { toasts[control].count += 1; @@ -441,14 +451,31 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t main_button->queue_redraw(); } - // Retrieve the label back then update the text. - Label *label = Object::cast_to<Label>(control->get_child(0)->get_child(0)); - ERR_FAIL_COND(!label); + // Retrieve the label back, then update the text. + Label *message_label = toasts[control].message_label; + ERR_FAIL_COND(!message_label); + message_label->set_text(p_message); + message_label->set_text_overrun_behavior(TextServer::OVERRUN_NO_TRIMMING); + message_label->set_custom_minimum_size(Size2()); + + Size2i size = message_label->get_combined_minimum_size(); + int limit_width = get_viewport_rect().size.x / 2; // Limit label size to half the viewport size. + if (size.x > limit_width) { + message_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); + message_label->set_custom_minimum_size(Size2(limit_width, 0)); + } + + // Retrieve the count label back, then update the text. + Label *message_count_label = toasts[control].message_count_label; if (toasts[control].count == 1) { - label->set_text(p_message); + message_count_label->hide(); } else { - label->set_text(vformat("%s (%d)", p_message, toasts[control].count)); + message_count_label->set_text(vformat("(%d)", toasts[control].count)); + message_count_label->show(); } + + vbox_container->reset_size(); + is_processing_error = false; } @@ -498,7 +525,7 @@ EditorToaster::EditorToaster() { Ref<StyleBoxFlat> boxes[] = { info_panel_style_background, warning_panel_style_background, error_panel_style_background }; for (int i = 0; i < 3; i++) { - boxes[i]->set_default_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3); + boxes[i]->set_content_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3); } // Theming (progress). diff --git a/editor/editor_toaster.h b/editor/editor_toaster.h index acd2a8fbf3..6b834f8288 100644 --- a/editor/editor_toaster.h +++ b/editor/editor_toaster.h @@ -79,6 +79,8 @@ private: String message; String tooltip; int count = 0; + Label *message_label = nullptr; + Label *message_count_label = nullptr; }; HashMap<Control *, Toast> toasts; diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index cc96107f97..1d147cc5b9 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -77,7 +77,6 @@ void EditorExport::_save() { config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter()); config->set_value(section, "encrypt_pck", preset->get_enc_pck()); config->set_value(section, "encrypt_directory", preset->get_enc_directory()); - config->set_value(section, "script_export_mode", preset->get_script_export_mode()); config->set_value(section, "script_encryption_key", preset->get_script_encryption_key()); String option_section = "preset." + itos(i) + ".options"; @@ -264,9 +263,6 @@ void EditorExport::load_config() { if (config->has_section_key(section, "encryption_exclude_filters")) { preset->set_enc_ex_filter(config->get_value(section, "encryption_exclude_filters")); } - if (config->has_section_key(section, "script_export_mode")) { - preset->set_script_export_mode(config->get_value(section, "script_export_mode")); - } if (config->has_section_key(section, "script_encryption_key")) { preset->set_script_encryption_key(config->get_value(section, "script_encryption_key")); } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index cacd181ad8..8da52e20f7 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -503,8 +503,8 @@ bool EditorExportPlatform::_export_customize_dictionary(Dictionary &dict, LocalV case Variant::OBJECT: { Ref<Resource> res = v; if (res.is_valid()) { - for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) { - Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, ""); + for (Ref<EditorExportPlugin> &plugin : customize_resources_plugins) { + Ref<Resource> new_res = plugin->_customize_resource(res, ""); if (new_res.is_valid()) { changed = true; if (new_res != res) { @@ -550,8 +550,8 @@ bool EditorExportPlatform::_export_customize_array(Array &arr, LocalVector<Ref<E case Variant::OBJECT: { Ref<Resource> res = v; if (res.is_valid()) { - for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) { - Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, ""); + for (Ref<EditorExportPlugin> &plugin : customize_resources_plugins) { + Ref<Resource> new_res = plugin->_customize_resource(res, ""); if (new_res.is_valid()) { changed = true; if (new_res != res) { @@ -597,8 +597,8 @@ bool EditorExportPlatform::_export_customize_object(Object *p_object, LocalVecto case Variant::OBJECT: { Ref<Resource> res = p_object->get(E.name); if (res.is_valid()) { - for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) { - Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, ""); + for (Ref<EditorExportPlugin> &plugin : customize_resources_plugins) { + Ref<Resource> new_res = plugin->_customize_resource(res, ""); if (new_res.is_valid()) { changed = true; if (new_res != res) { @@ -715,16 +715,16 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector ERR_FAIL_COND_V(ps.is_null(), p_path); Node *node = ps->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); // Make sure the child scene root gets the correct inheritance chain. ERR_FAIL_COND_V(node == nullptr, p_path); - if (customize_scenes_plugins.size()) { - for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) { - Node *customized = customize_scenes_plugins[i]->_customize_scene(node, p_path); + if (!customize_scenes_plugins.is_empty()) { + for (Ref<EditorExportPlugin> &plugin : customize_scenes_plugins) { + Node *customized = plugin->_customize_scene(node, p_path); if (customized != nullptr) { node = customized; modified = true; } } } - if (customize_resources_plugins.size()) { + if (!customize_resources_plugins.is_empty()) { if (_export_customize_scene_resources(node, node, customize_resources_plugins)) { modified = true; } @@ -746,9 +746,9 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector Ref<Resource> res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE); ERR_FAIL_COND_V(res.is_null(), p_path); - if (customize_resources_plugins.size()) { - for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) { - Ref<Resource> new_res = customize_resources_plugins[i]->_customize_resource(res, p_path); + if (!customize_resources_plugins.is_empty()) { + for (Ref<EditorExportPlugin> &plugin : customize_resources_plugins) { + Ref<Resource> new_res = plugin->_customize_resource(res, p_path); if (new_res.is_valid()) { modified = true; if (new_res != res) { @@ -960,7 +960,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & bool convert_text_to_binary = GLOBAL_GET("editor/export/convert_text_resources_to_binary"); - if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) { + if (convert_text_to_binary || !customize_resources_plugins.is_empty() || !customize_scenes_plugins.is_empty()) { // See if we have something to open Ref<FileAccess> f = FileAccess::open(export_base_path.path_join("file_cache"), FileAccess::READ); if (f.is_valid()) { @@ -1179,7 +1179,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & idx++; } - if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) { + if (convert_text_to_binary || !customize_resources_plugins.is_empty() || !customize_scenes_plugins.is_empty()) { // End scene customization String fcache = export_base_path.path_join("file_cache"); @@ -1196,12 +1196,12 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & ERR_PRINT("Error opening export file cache: " + fcache); } - for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) { - customize_resources_plugins[i]->_end_customize_resources(); + for (Ref<EditorExportPlugin> &plugin : customize_resources_plugins) { + plugin->_end_customize_resources(); } - for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) { - customize_scenes_plugins[i]->_end_customize_scenes(); + for (Ref<EditorExportPlugin> &plugin : customize_scenes_plugins) { + plugin->_end_customize_scenes(); } } //save config! diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index 784dbc116a..dfd4520eec 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -227,8 +227,6 @@ void EditorExportPlugin::_bind_methods() { } EditorExportPlugin::EditorExportPlugin() { - GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false); - EDITOR_DEF("export/ssh/ssh", ""); EDITOR_DEF("export/ssh/scp", ""); } diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp index 6cd8e85e6a..c6365806b3 100644 --- a/editor/export/editor_export_preset.cpp +++ b/editor/export/editor_export_preset.cpp @@ -203,15 +203,6 @@ bool EditorExportPreset::get_enc_directory() const { return enc_directory; } -void EditorExportPreset::set_script_export_mode(int p_mode) { - script_mode = p_mode; - EditorExport::singleton->save_presets(); -} - -int EditorExportPreset::get_script_export_mode() const { - return script_mode; -} - void EditorExportPreset::set_script_encryption_key(const String &p_key) { script_key = p_key; EditorExport::singleton->save_presets(); diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h index 2055416d4b..de208f410e 100644 --- a/editor/export/editor_export_preset.h +++ b/editor/export/editor_export_preset.h @@ -46,11 +46,6 @@ public: EXCLUDE_SELECTED_RESOURCES, }; - enum ScriptExportMode { - MODE_SCRIPT_TEXT, - MODE_SCRIPT_COMPILED, - }; - private: Ref<EditorExportPlatform> platform; ExportFilter export_filter = EXPORT_ALL_RESOURCES; @@ -78,7 +73,6 @@ private: bool enc_pck = false; bool enc_directory = false; - int script_mode = MODE_SCRIPT_COMPILED; String script_key; protected: @@ -132,9 +126,6 @@ public: void set_enc_directory(bool p_enabled); bool get_enc_directory() const; - void set_script_export_mode(int p_mode); - int get_script_export_mode() const; - void set_script_encryption_key(const String &p_key); String get_script_encryption_key() const; diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 7136b4ceb6..2caebc6f04 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -317,9 +317,6 @@ void ProjectExportDialog::_edit_preset(int p_index) { bool enc_directory_mode = current->get_enc_directory(); enc_directory->set_pressed(enc_directory_mode); - int script_export_mode = current->get_script_export_mode(); - script_mode->select(script_export_mode); - String key = current->get_script_encryption_key(); if (!updating_script_key) { script_key->set_text(key); @@ -513,19 +510,6 @@ void ProjectExportDialog::_enc_directory_changed(bool p_pressed) { _update_current_preset(); } -void ProjectExportDialog::_script_export_mode_changed(int p_mode) { - if (updating) { - return; - } - - Ref<EditorExportPreset> current = get_current_preset(); - ERR_FAIL_COND(current.is_null()); - - current->set_script_export_mode(p_mode); - - _update_current_preset(); -} - void ProjectExportDialog::_script_encryption_key_changed(const String &p_key) { if (updating) { return; @@ -979,9 +963,6 @@ void ProjectExportDialog::_export_all(bool p_debug) { } void ProjectExportDialog::_bind_methods() { - ClassDB::bind_method("_get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw); - ClassDB::bind_method("_can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &ProjectExportDialog::drop_data_fw); ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all); ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path); ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path); @@ -1022,8 +1003,7 @@ ProjectExportDialog::ProjectExportDialog() { preset_vb->add_child(mc); mc->set_v_size_flags(Control::SIZE_EXPAND_FILL); presets = memnew(ItemList); - // TODO: Must reimplement drag forwarding. - //presets->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(presets, ProjectExportDialog); mc->add_child(presets); presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset)); duplicate_preset = memnew(Button); @@ -1115,12 +1095,6 @@ ProjectExportDialog::ProjectExportDialog() { exclude_filters); exclude_filters->connect("text_changed", callable_mp(this, &ProjectExportDialog::_filter_changed)); - script_mode = memnew(OptionButton); - resources_vb->add_margin_child(TTR("GDScript Export Mode:"), script_mode); - script_mode->add_item(TTR("Text"), (int)EditorExportPreset::MODE_SCRIPT_TEXT); - script_mode->add_item(TTR("Compiled Bytecode (Faster Loading)"), (int)EditorExportPreset::MODE_SCRIPT_COMPILED); - script_mode->connect("item_selected", callable_mp(this, &ProjectExportDialog::_script_export_mode_changed)); - // Feature tags. VBoxContainer *feature_vb = memnew(VBoxContainer); diff --git a/editor/export/project_export.h b/editor/export/project_export.h index 1138d598cb..d392dba2a4 100644 --- a/editor/export/project_export.h +++ b/editor/export/project_export.h @@ -86,7 +86,6 @@ private: LineEdit *custom_features = nullptr; RichTextLabel *custom_feature_display = nullptr; - OptionButton *script_mode = nullptr; LineEdit *script_key = nullptr; Label *script_key_error = nullptr; @@ -152,7 +151,6 @@ private: void _enc_pck_changed(bool p_pressed); void _enc_directory_changed(bool p_pressed); void _enc_filters_changed(const String &p_text); - void _script_export_mode_changed(int p_mode); void _script_encryption_key_changed(const String &p_key); bool _validate_script_encryption_key(const String &p_key); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 17cdab60c8..a078c58e72 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1819,6 +1819,43 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected OS::get_singleton()->shell_open(String("file://") + dir); } break; + case FILE_OPEN_EXTERNAL: { + String fpath = path; + if (path == "Favorites") { + fpath = p_selected[0]; + } + + String file = ProjectSettings::get_singleton()->globalize_path(fpath); + + String resource_type = ResourceLoader::get_resource_type(fpath); + String external_program; + + if (resource_type == "CompressedTexture2D" || resource_type == "Image") { + if (file.get_extension() == "svg" || file.get_extension() == "svgz") { + external_program = EDITOR_GET("filesystem/external_programs/vector_image_editor"); + } else { + external_program = EDITOR_GET("filesystem/external_programs/raster_image_editor"); + } + } else if (ClassDB::is_parent_class(resource_type, "AudioStream")) { + external_program = EDITOR_GET("filesystem/external_programs/audio_editor"); + } else if (resource_type == "PackedScene") { + // Ignore non-model scenes. + if (file.get_extension() != "tscn" && file.get_extension() != "scn" && file.get_extension() != "res") { + external_program = EDITOR_GET("filesystem/external_programs/3d_model_editor"); + } + } else if (ClassDB::is_parent_class(resource_type, "Script")) { + external_program = EDITOR_GET("text_editor/external/exec_path"); + } + + if (external_program.is_empty()) { + OS::get_singleton()->shell_open(file); + } else { + List<String> args; + args.push_back(file); + OS::get_singleton()->create_process(external_program, args); + } + } break; + case FILE_OPEN: { // Open folders. TreeItem *selected = tree->get_root(); @@ -2590,18 +2627,29 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str if (p_paths.size() == 1) { p_popup->add_separator(); if (p_display_path_dependent_options) { - p_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER); - p_popup->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("New Scene..."), FILE_NEW_SCENE); - p_popup->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("New Script..."), FILE_NEW_SCRIPT); - p_popup->add_icon_item(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")), TTR("New Resource..."), FILE_NEW_RESOURCE); - p_popup->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("New TextFile..."), FILE_NEW_TEXTFILE); + PopupMenu *new_menu = memnew(PopupMenu); + new_menu->set_name("New"); + new_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option)); + + p_popup->add_child(new_menu); + p_popup->add_submenu_item(TTR("New"), "New"); + + new_menu->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("Folder..."), FILE_NEW_FOLDER); + new_menu->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("Scene..."), FILE_NEW_SCENE); + new_menu->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("Script..."), FILE_NEW_SCRIPT); + new_menu->add_icon_item(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")), TTR("Resource..."), FILE_NEW_RESOURCE); + new_menu->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("TextFile..."), FILE_NEW_TEXTFILE); p_popup->add_separator(); } String fpath = p_paths[0]; - String item_text = fpath.ends_with("/") ? TTR("Open in File Manager") : TTR("Show in File Manager"); + bool is_directory = fpath.ends_with("/"); + String item_text = is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager"); p_popup->add_icon_shortcut(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), item_text); + if (!is_directory) { + p_popup->add_icon_shortcut(get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL); + } path = fpath; } } @@ -2707,6 +2755,7 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton file_list_popup->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("New TextFile..."), FILE_NEW_TEXTFILE); file_list_popup->add_separator(); file_list_popup->add_icon_shortcut(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); + file_list_popup->set_position(files->get_screen_position() + p_pos); file_list_popup->reset_size(); file_list_popup->popup(); @@ -2820,6 +2869,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) { _tree_rmb_option(FILE_RENAME); } else if (ED_IS_SHORTCUT("filesystem_dock/show_in_explorer", p_event)) { _tree_rmb_option(FILE_SHOW_IN_EXPLORER); + } else if (ED_IS_SHORTCUT("filesystem_dock/open_in_external_program", p_event)) { + _tree_rmb_option(FILE_OPEN_EXTERNAL); } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) { focus_on_filter(); } else { @@ -2890,12 +2941,19 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) { } } -void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &r_files) const { +bool FileSystemDock::_get_imported_files(const String &p_path, String &r_extension, Vector<String> &r_files) const { if (!p_path.ends_with("/")) { if (FileAccess::exists(p_path + ".import")) { + if (r_extension.is_empty()) { + r_extension = p_path.get_extension(); + } else if (r_extension != p_path.get_extension()) { + r_files.clear(); + return false; // File type mismatch, stop search. + } + r_files.push_back(p_path); } - return; + return true; } Ref<DirAccess> da = DirAccess::open(p_path); @@ -2904,11 +2962,14 @@ void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &r while (!n.is_empty()) { if (n != "." && n != ".." && !n.ends_with(".import")) { String npath = p_path + n + (da->current_is_dir() ? "/" : ""); - _get_imported_files(npath, r_files); + if (!_get_imported_files(npath, r_extension, r_files)) { + return false; + } } n = da->get_next(); } da->list_dir_end(); + return true; } void FileSystemDock::_update_import_dock() { @@ -2933,10 +2994,16 @@ void FileSystemDock::_update_import_dock() { } } - // Expand directory selection + if (!selected.is_empty() && selected[0] == "res://") { + // Scanning res:// is costly and unlikely to yield any useful results. + return; + } + + // Expand directory selection. Vector<String> efiles; - for (int i = 0; i < selected.size(); i++) { - _get_imported_files(selected[i], efiles); + String extension; + for (const String &fpath : selected) { + _get_imported_files(fpath, extension, efiles); } // Check import. @@ -3021,9 +3088,6 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done); ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw); ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path); ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock); @@ -3052,6 +3116,7 @@ FileSystemDock::FileSystemDock() { ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), Key::F2); ED_SHORTCUT_OVERRIDE("filesystem_dock/rename", "macos", Key::ENTER); ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager")); + ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program")); VBoxContainer *top_vbc = memnew(VBoxContainer); add_child(top_vbc); @@ -3123,10 +3188,11 @@ FileSystemDock::FileSystemDock() { tree = memnew(Tree); tree->set_hide_root(true); - tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(tree, FileSystemDock); tree->set_allow_rmb_select(true); tree->set_select_mode(Tree::SELECT_MULTI); tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE)); + tree->set_column_clip_content(0, true); split_box->add_child(tree); tree->connect("item_activated", callable_mp(this, &FileSystemDock::_tree_activate_file)); @@ -3160,7 +3226,7 @@ FileSystemDock::FileSystemDock() { files = memnew(ItemList); files->set_v_size_flags(SIZE_EXPAND_FILL); files->set_select_mode(ItemList::SELECT_MULTI); - files->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(files, FileSystemDock); files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked)); files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input)); files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected)); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 2304d8f8ad..42a72b7ee8 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -94,6 +94,7 @@ private: FILE_NEW_SCRIPT, FILE_NEW_SCENE, FILE_SHOW_IN_EXPLORER, + FILE_OPEN_EXTERNAL, FILE_COPY_PATH, FILE_COPY_UID, FILE_NEW_RESOURCE, @@ -213,7 +214,7 @@ private: void _file_multi_selected(int p_index, bool p_selected); void _tree_multi_selected(Object *p_item, int p_column, bool p_selected); - void _get_imported_files(const String &p_path, Vector<String> &r_files) const; + bool _get_imported_files(const String &p_path, String &r_extension, Vector<String> &r_files) const; void _update_import_dock(); void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const; diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index fcd706627d..a8d746fde6 100644 --- a/editor/import/collada.cpp +++ b/editor/import/collada.cpp @@ -262,7 +262,7 @@ void Collada::_parse_asset(XMLParser &parser) { COLLADA_PRINT("up axis: " + parser.get_node_data()); } else if (name == "unit") { - state.unit_scale = parser.get_attribute_value("meter").to_float(); + state.unit_scale = parser.get_named_attribute_value("meter").to_float(); COLLADA_PRINT("unit scale: " + rtos(state.unit_scale)); } @@ -273,7 +273,7 @@ void Collada::_parse_asset(XMLParser &parser) { } void Collada::_parse_image(XMLParser &parser) { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); if (!(state.import_flags & IMPORT_FLAG_SCENE)) { if (!parser.is_empty()) { @@ -286,7 +286,7 @@ void Collada::_parse_image(XMLParser &parser) { if (state.version < State::Version(1, 4, 0)) { /* <1.4 */ - String path = parser.get_attribute_value("source").strip_edges(); + String path = parser.get_named_attribute_value("source").strip_edges(); if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode())); @@ -337,9 +337,9 @@ void Collada::_parse_material(XMLParser &parser) { Material material; - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); if (parser.has_attribute("name")) { - material.name = parser.get_attribute_value("name"); + material.name = parser.get_named_attribute_value("name"); } if (state.version < State::Version(1, 4, 0)) { @@ -348,7 +348,7 @@ void Collada::_parse_material(XMLParser &parser) { } else { while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") { - material.instance_effect = _uri_to_id(parser.get_attribute_value("url")); + material.instance_effect = _uri_to_id(parser.get_named_attribute_value("url")); } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material") { break; //end of <asset> } @@ -549,7 +549,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String & _parse_effect_material(parser, effect, id); // try again } else if (parser.get_node_name() == "newparam") { - String name = parser.get_attribute_value("sid"); + String name = parser.get_named_attribute_value("sid"); Variant value = _parse_param(parser); effect.params[name] = value; COLLADA_PRINT("param: " + name + " value:" + String(value)); @@ -591,7 +591,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String & } } else if (parser.get_node_name() == "texture") { - String sampler = parser.get_attribute_value("texture"); + String sampler = parser.get_named_attribute_value("texture"); if (!effect.params.has(sampler)) { ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data()); } else { @@ -609,7 +609,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String & } else if (what == "emission") { effect.emission.texture = uri; } else if (what == "bump") { - if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") { + if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") { WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported."); } @@ -654,7 +654,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String & while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "texture") { - String sampler = parser.get_attribute_value("texture"); + String sampler = parser.get_named_attribute_value("texture"); if (!effect.params.has(sampler)) { ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data()); } else { @@ -665,7 +665,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String & } else { String uri = effect.params[surface]; - if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") { + if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") { WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported."); } @@ -703,11 +703,11 @@ void Collada::_parse_effect(XMLParser &parser) { return; } - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); Effect effect; if (parser.has_attribute("name")) { - effect.name = parser.get_attribute_value("name"); + effect.name = parser.get_named_attribute_value("name"); } _parse_effect_material(parser, effect, id); @@ -724,7 +724,7 @@ void Collada::_parse_camera(XMLParser &parser) { return; } - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); state.camera_data_map[id] = CameraData(); CameraData &camera = state.camera_data_map[id]; @@ -780,7 +780,7 @@ void Collada::_parse_light(XMLParser &parser) { return; } - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); state.light_data_map[id] = LightData(); LightData &light = state.light_data_map[id]; @@ -848,7 +848,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam CurveData &curvedata = state.curve_data_map[p_id]; curvedata.name = p_name; - String closed = parser.get_attribute_value_safe("closed").to_lower(); + String closed = parser.get_named_attribute_value_safe("closed").to_lower(); curvedata.closed = closed == "true" || closed == "1"; COLLADA_PRINT("curve name: " + p_name); @@ -865,7 +865,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam String section = parser.get_node_name(); if (section == "source") { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); curvedata.sources[id] = CurveData::Source(); current_source = id; COLLADA_PRINT("source data: " + id); @@ -888,15 +888,15 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam } else if (section == "accessor") { // child of source (below a technique tag) if (curvedata.sources.has(current_source)) { - curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int(); + curvedata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int(); COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride)); } } else if (section == "control_vertices") { while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "input") { - String semantic = parser.get_attribute_value("semantic"); - String source = _uri_to_id(parser.get_attribute_value("source")); + String semantic = parser.get_named_attribute_value("semantic"); + String source = _uri_to_id(parser.get_named_attribute_value("source")); curvedata.control_vertices[semantic] = source; @@ -945,7 +945,7 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name String section = parser.get_node_name(); if (section == "source") { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); meshdata.sources[id] = MeshData::Source(); current_source = id; COLLADA_PRINT("source data: " + id); @@ -961,19 +961,19 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name } else if (section == "accessor") { // child of source (below a technique tag) if (meshdata.sources.has(current_source)) { - meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int(); + meshdata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int(); COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride)); } } else if (section == "vertices") { MeshData::Vertices vert; - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); int last_ref = 0; while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "input") { - String semantic = parser.get_attribute_value("semantic"); - String source = _uri_to_id(parser.get_attribute_value("source")); + String semantic = parser.get_named_attribute_value("semantic"); + String source = _uri_to_id(parser.get_named_attribute_value("source")); if (semantic == "TEXCOORD") { semantic = "TEXCOORD" + itos(last_ref++); @@ -998,22 +998,22 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name MeshData::Primitives prim; if (parser.has_attribute("material")) { - prim.material = parser.get_attribute_value("material"); + prim.material = parser.get_named_attribute_value("material"); } - prim.count = parser.get_attribute_value("count").to_int(); + prim.count = parser.get_named_attribute_value("count").to_int(); prim.vertex_size = 0; int last_ref = 0; while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "input") { - String semantic = parser.get_attribute_value("semantic"); - String source = _uri_to_id(parser.get_attribute_value("source")); + String semantic = parser.get_named_attribute_value("semantic"); + String source = _uri_to_id(parser.get_named_attribute_value("source")); if (semantic == "TEXCOORD") { semantic = "TEXCOORD" + itos(last_ref++); } - int offset = parser.get_attribute_value("offset").to_int(); + int offset = parser.get_named_attribute_value("offset").to_int(); MeshData::Primitives::SourceRef sref; sref.source = source; @@ -1074,7 +1074,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { state.skin_controller_data_map[p_id] = SkinControllerData(); SkinControllerData &skindata = state.skin_controller_data_map[p_id]; - skindata.base = _uri_to_id(parser.get_attribute_value("source")); + skindata.base = _uri_to_id(parser.get_named_attribute_value("source")); String current_source; @@ -1091,7 +1091,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape); } else if (section == "source") { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); skindata.sources[id] = SkinControllerData::Source(); current_source = id; COLLADA_PRINT("source data: " + id); @@ -1125,7 +1125,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { if (skindata.sources.has(current_source)) { int stride = 1; if (parser.has_attribute("stride")) { - stride = parser.get_attribute_value("stride").to_int(); + stride = parser.get_named_attribute_value("stride").to_int(); } skindata.sources[current_source].stride = stride; @@ -1138,8 +1138,8 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "input") { - String semantic = parser.get_attribute_value("semantic"); - String source = _uri_to_id(parser.get_attribute_value("source")); + String semantic = parser.get_named_attribute_value("semantic"); + String source = _uri_to_id(parser.get_named_attribute_value("source")); joint.sources[semantic] = source; @@ -1155,15 +1155,15 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { } else if (section == "vertex_weights") { SkinControllerData::Weights weights; - weights.count = parser.get_attribute_value("count").to_int(); + weights.count = parser.get_named_attribute_value("count").to_int(); while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "input") { - String semantic = parser.get_attribute_value("semantic"); - String source = _uri_to_id(parser.get_attribute_value("source")); + String semantic = parser.get_named_attribute_value("semantic"); + String source = _uri_to_id(parser.get_named_attribute_value("source")); - int offset = parser.get_attribute_value("offset").to_int(); + int offset = parser.get_named_attribute_value("offset").to_int(); SkinControllerData::Weights::SourceRef sref; sref.source = source; @@ -1228,8 +1228,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { state.morph_controller_data_map[p_id] = MorphControllerData(); MorphControllerData &morphdata = state.morph_controller_data_map[p_id]; - morphdata.mesh = _uri_to_id(parser.get_attribute_value("source")); - morphdata.mode = parser.get_attribute_value("method"); + morphdata.mesh = _uri_to_id(parser.get_named_attribute_value("source")); + morphdata.mode = parser.get_named_attribute_value("method"); String current_source; while (parser.read() == OK) { @@ -1237,7 +1237,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { String section = parser.get_node_name(); if (section == "source") { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); morphdata.sources[id] = MorphControllerData::Source(); current_source = id; COLLADA_PRINT("source data: " + id); @@ -1261,7 +1261,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { if (morphdata.sources.has(current_source)) { int stride = 1; if (parser.has_attribute("stride")) { - stride = parser.get_attribute_value("stride").to_int(); + stride = parser.get_named_attribute_value("stride").to_int(); } morphdata.sources[current_source].stride = stride; @@ -1272,8 +1272,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "input") { - String semantic = parser.get_attribute_value("semantic"); - String source = _uri_to_id(parser.get_attribute_value("source")); + String semantic = parser.get_named_attribute_value("semantic"); + String source = _uri_to_id(parser.get_named_attribute_value("source")); morphdata.targets[semantic] = source; @@ -1295,7 +1295,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { } void Collada::_parse_controller(XMLParser &parser) { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); if (parser.is_empty()) { return; @@ -1320,7 +1320,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) { String type = parser.get_node_name(); NodeGeometry *geom = memnew(NodeGeometry); geom->controller = type == "instance_controller"; - geom->source = _uri_to_id(parser.get_attribute_value_safe("url")); + geom->source = _uri_to_id(parser.get_named_attribute_value_safe("url")); if (parser.is_empty()) { //nothing else to parse... return geom; @@ -1329,8 +1329,8 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) { while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "instance_material") { - String symbol = parser.get_attribute_value("symbol"); - String target = _uri_to_id(parser.get_attribute_value("target")); + String symbol = parser.get_named_attribute_value("symbol"); + String target = _uri_to_id(parser.get_named_attribute_value("target")); NodeGeometry::Material mat; mat.target = target; @@ -1370,7 +1370,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) { Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) { NodeCamera *cam = memnew(NodeCamera); - cam->camera = _uri_to_id(parser.get_attribute_value_safe("url")); + cam->camera = _uri_to_id(parser.get_named_attribute_value_safe("url")); if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5); @@ -1391,7 +1391,7 @@ Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) { Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) { NodeLight *cam = memnew(NodeLight); - cam->light = _uri_to_id(parser.get_attribute_value_safe("url")); + cam->light = _uri_to_id(parser.get_named_attribute_value_safe("url")); if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5); @@ -1437,7 +1437,7 @@ Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) { Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { String name; - String id = parser.get_attribute_value_safe("id"); + String id = parser.get_named_attribute_value_safe("id"); bool found_name = false; @@ -1455,25 +1455,25 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { Node *node = nullptr; - name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id"); + name = parser.has_attribute("name") ? parser.get_named_attribute_value_safe("name") : parser.get_named_attribute_value_safe("id"); if (name.is_empty()) { name = id; } else { found_name = true; } - if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) { + if ((parser.has_attribute("type") && parser.get_named_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) { // handle a bone NodeJoint *joint = memnew(NodeJoint); if (parser.has_attribute("sid")) { //bones may not have sid - joint->sid = parser.get_attribute_value("sid"); + joint->sid = parser.get_named_attribute_value("sid"); //state.bone_map[joint->sid]=joint; } else if (state.idref_joints.has(name)) { joint->sid = name; //kind of a cheat but.. } else if (parser.has_attribute("name")) { - joint->sid = parser.get_attribute_value_safe("name"); + joint->sid = parser.get_named_attribute_value_safe("name"); } if (!joint->sid.is_empty()) { @@ -1490,7 +1490,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { if (section == "translate") { Node::XForm xf; if (parser.has_attribute("sid")) { - xf.id = parser.get_attribute_value("sid"); + xf.id = parser.get_named_attribute_value("sid"); } xf.op = Node::XForm::OP_TRANSLATE; @@ -1501,7 +1501,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { } else if (section == "rotate") { Node::XForm xf; if (parser.has_attribute("sid")) { - xf.id = parser.get_attribute_value("sid"); + xf.id = parser.get_named_attribute_value("sid"); } xf.op = Node::XForm::OP_ROTATE; @@ -1513,7 +1513,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { } else if (section == "scale") { Node::XForm xf; if (parser.has_attribute("sid")) { - xf.id = parser.get_attribute_value("sid"); + xf.id = parser.get_named_attribute_value("sid"); } xf.op = Node::XForm::OP_SCALE; @@ -1527,7 +1527,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { } else if (section == "matrix") { Node::XForm xf; if (parser.has_attribute("sid")) { - xf.id = parser.get_attribute_value("sid"); + xf.id = parser.get_named_attribute_value("sid"); } xf.op = Node::XForm::OP_MATRIX; @@ -1544,7 +1544,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { } else if (section == "visibility") { Node::XForm xf; if (parser.has_attribute("sid")) { - xf.id = parser.get_attribute_value("sid"); + xf.id = parser.get_named_attribute_value("sid"); } xf.op = Node::XForm::OP_VISIBILITY; @@ -1609,7 +1609,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { } void Collada::_parse_visual_scene(XMLParser &parser) { - String id = parser.get_attribute_value("id"); + String id = parser.get_named_attribute_value("id"); if (parser.is_empty()) { return; @@ -1619,7 +1619,7 @@ void Collada::_parse_visual_scene(XMLParser &parser) { VisualScene &vscene = state.visual_scene_map[id]; if (parser.has_attribute("name")) { - vscene.name = parser.get_attribute_value("name"); + vscene.name = parser.get_named_attribute_value("name"); } while (parser.read() == OK) { @@ -1656,7 +1656,7 @@ void Collada::_parse_animation(XMLParser &parser) { String id = ""; if (parser.has_attribute("id")) { - id = parser.get_attribute_value("id"); + id = parser.get_named_attribute_value("id"); } String current_source; @@ -1668,7 +1668,7 @@ void Collada::_parse_animation(XMLParser &parser) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser.get_node_name(); if (name == "source") { - current_source = parser.get_attribute_value("id"); + current_source = parser.get_named_attribute_value("id"); source_param_names[current_source] = Vector<String>(); source_param_types[current_source] = Vector<String>(); @@ -1683,32 +1683,32 @@ void Collada::_parse_animation(XMLParser &parser) { } } else if (name == "accessor") { if (!current_source.is_empty() && parser.has_attribute("stride")) { - source_strides[current_source] = parser.get_attribute_value("stride").to_int(); + source_strides[current_source] = parser.get_named_attribute_value("stride").to_int(); } } else if (name == "sampler") { - current_sampler = parser.get_attribute_value("id"); + current_sampler = parser.get_named_attribute_value("id"); samplers[current_sampler] = HashMap<String, String>(); } else if (name == "param") { if (parser.has_attribute("name")) { - source_param_names[current_source].push_back(parser.get_attribute_value("name")); + source_param_names[current_source].push_back(parser.get_named_attribute_value("name")); } else { source_param_names[current_source].push_back(""); } if (parser.has_attribute("type")) { - source_param_types[current_source].push_back(parser.get_attribute_value("type")); + source_param_types[current_source].push_back(parser.get_named_attribute_value("type")); } else { source_param_types[current_source].push_back(""); } } else if (name == "input") { if (!current_sampler.is_empty()) { - samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source"); + samplers[current_sampler][parser.get_named_attribute_value("semantic")] = parser.get_named_attribute_value("source"); } } else if (name == "channel") { - channel_sources.push_back(parser.get_attribute_value("source")); - channel_targets.push_back(parser.get_attribute_value("target")); + channel_sources.push_back(parser.get_named_attribute_value("source")); + channel_targets.push_back(parser.get_named_attribute_value("target")); } } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation") { @@ -1857,22 +1857,22 @@ void Collada::_parse_animation_clip(XMLParser &parser) { AnimationClip clip; if (parser.has_attribute("name")) { - clip.name = parser.get_attribute_value("name"); + clip.name = parser.get_named_attribute_value("name"); } else if (parser.has_attribute("id")) { - clip.name = parser.get_attribute_value("id"); + clip.name = parser.get_named_attribute_value("id"); } if (parser.has_attribute("start")) { - clip.begin = parser.get_attribute_value("start").to_float(); + clip.begin = parser.get_named_attribute_value("start").to_float(); } if (parser.has_attribute("end")) { - clip.end = parser.get_attribute_value("end").to_float(); + clip.end = parser.get_named_attribute_value("end").to_float(); } while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser.get_node_name(); if (name == "instance_animation") { - String url = _uri_to_id(parser.get_attribute_value("url")); + String url = _uri_to_id(parser.get_named_attribute_value("url")); clip.tracks.push_back(url); } @@ -1894,9 +1894,9 @@ void Collada::_parse_scene(XMLParser &parser) { String name = parser.get_node_name(); if (name == "instance_visual_scene") { - state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url")); + state.root_visual_scene = _uri_to_id(parser.get_named_attribute_value("url")); } else if (name == "instance_physics_scene") { - state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url")); + state.root_physics_scene = _uri_to_id(parser.get_named_attribute_value("url")); } } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene") { @@ -1925,8 +1925,8 @@ void Collada::_parse_library(XMLParser &parser) { } else if (name == "light") { _parse_light(parser); } else if (name == "geometry") { - String id = parser.get_attribute_value("id"); - String name2 = parser.get_attribute_value_safe("name"); + String id = parser.get_named_attribute_value("id"); + String name2 = parser.get_named_attribute_value_safe("name"); while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "mesh") { @@ -2346,7 +2346,7 @@ Error Collada::load(const String &p_path, int p_flags) { { //version - String version = parser.get_attribute_value("version"); + String version = parser.get_named_attribute_value("version"); state.version.major = version.get_slice(".", 0).to_int(); state.version.minor = version.get_slice(".", 1).to_int(); state.version.rev = version.get_slice(".", 2).to_int(); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 4b0ece3367..1ffede6502 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -734,7 +734,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p /* CREATE PRIMITIVE ARRAY */ /**************************/ - // The way collada uses indices is more optimal, and friendlier with 3D modelling software, + // The way collada uses indices is more optimal, and friendlier with 3D modeling software, // because it can index everything, not only vertices (similar to how the WII works). // This is, however, more incompatible with standard video cards, so arrays must be converted. // Must convert to GL/DX format. diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index f1fd1d5a03..3dd01754a3 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -206,6 +206,20 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); + // Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree) + // This should only match, if it's indeed a COFF file header + // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types + const int first_bytes = f->get_16(); + static const Vector<int> coff_header_machines{ + 0x0, // IMAGE_FILE_MACHINE_UNKNOWN + 0x8664, // IMAGE_FILE_MACHINE_AMD64 + 0x1c0, // IMAGE_FILE_MACHINE_ARM + 0x14c, // IMAGE_FILE_MACHINE_I386 + 0x200, // IMAGE_FILE_MACHINE_IA64 + }; + ERR_FAIL_COND_V_MSG(coff_header_machines.find(first_bytes) != -1, ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path)); + f->seek(0); + Ref<ArrayMesh> mesh; mesh.instantiate(); @@ -218,7 +232,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ Vector<Vector3> normals; Vector<Vector2> uvs; Vector<Color> colors; - String name; + const String default_name = "Mesh"; + String name = default_name; HashMap<String, HashMap<String, Ref<StandardMaterial3D>>> material_map; @@ -395,9 +410,12 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ if (l.begins_with("o ") || f->eof_reached()) { if (!p_single_mesh) { - mesh->set_name(name); - r_meshes.push_back(mesh); - mesh.instantiate(); + if (mesh->get_surface_count() > 0) { + mesh->set_name(name); + r_meshes.push_back(mesh); + mesh.instantiate(); + } + name = default_name; current_group = ""; current_material = ""; } @@ -460,6 +478,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co for (const Ref<Mesh> &m : meshes) { Ref<ImporterMesh> mesh; mesh.instantiate(); + mesh->set_name(m->get_name()); for (int i = 0; i < m->get_surface_count(); i++) { mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i)); } diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index f6ec7da158..044f7475c2 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -703,15 +703,17 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) { } MeshData &md = mesh_map[p_id]; - if (p_from != mesh_tree) { - md.mesh_node->uncollapse_tree(); - md.mesh_node->select(0); - mesh_tree->ensure_cursor_is_visible(); - } - if (p_from != scene_tree) { - md.scene_node->uncollapse_tree(); - md.scene_node->select(0); - scene_tree->ensure_cursor_is_visible(); + if (md.mesh_node != nullptr) { + if (p_from != mesh_tree) { + md.mesh_node->uncollapse_tree(); + md.mesh_node->select(0); + mesh_tree->ensure_cursor_is_visible(); + } + if (p_from != scene_tree) { + md.scene_node->uncollapse_tree(); + md.scene_node->select(0); + scene_tree->ensure_cursor_is_visible(); + } } mesh_preview->set_mesh(md.mesh); @@ -1234,6 +1236,12 @@ SceneImportSettings::SceneImportSettings() { action_menu = memnew(MenuButton); action_menu->set_text(TTR("Actions...")); + // Style the MenuButton like a regular Button to make it more noticeable. + action_menu->set_flat(false); + action_menu->add_theme_style_override("normal", get_theme_stylebox("normal", "Button")); + action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button")); + action_menu->add_theme_style_override("pressed", get_theme_stylebox("pressed", "Button")); + action_menu->set_focus_mode(Control::FOCUS_ALL); menu_hb->add_child(action_menu); action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS); diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index 08d4bfff4a..4f7d99c567 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -169,7 +169,7 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven } if (k.is_valid()) { - k->set_pressed(false); // To avoid serialisation of 'pressed' property - doesn't matter for actions anyway. + k->set_pressed(false); // To avoid serialization of 'pressed' property - doesn't matter for actions anyway. // Maintain physical keycode option state if (physical_key_checkbox->is_pressed()) { k->set_keycode(Key::NONE); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index b28373e308..52482ecb16 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -189,8 +189,7 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) { int history_id = EditorUndoRedoManager::get_singleton()->get_history_for_object(current).id; EditorUndoRedoManager::get_singleton()->clear_history(true, history_id); - EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr); - EditorNode::get_singleton()->get_editor_plugins_over()->edit(current); + EditorNode::get_singleton()->edit_item(current, inspector); } } break; diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index 2a55ac949f..4f0db70681 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -48,6 +48,8 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name. name = "script"; + } else if (name.begins_with("Metadata/")) { + name = name.replace_first("Metadata/", "metadata/"); } Node *node_path_target = nullptr; @@ -98,6 +100,8 @@ bool MultiNodeEdit::_get(const StringName &p_name, Variant &r_ret) const { String name = p_name; if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name. name = "script"; + } else if (name.begins_with("Metadata/")) { + name = name.replace_first("Metadata/", "metadata/"); } for (const NodePath &E : nodes) { @@ -137,14 +141,18 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { List<PropertyInfo> plist; n->get_property_list(&plist, true); - for (const PropertyInfo &F : plist) { + for (PropertyInfo F : plist) { if (F.name == "script") { continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()). + } else if (F.name.begins_with("metadata/")) { + F.name = F.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from MultiNodeEdit. } + if (!usage.has(F.name)) { PLData pld; pld.uses = 0; pld.info = F; + pld.info.name = F.name; usage[F.name] = pld; data_list.push_back(usage.getptr(F.name)); } diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 4f6487fa77..97398b8b69 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -92,7 +92,7 @@ void PluginConfigDialog::_on_confirmed() { _clear_fields(); } -void PluginConfigDialog::_on_cancelled() { +void PluginConfigDialog::_on_canceled() { _clear_fields(); } @@ -162,7 +162,7 @@ void PluginConfigDialog::_notification(int p_what) { case NOTIFICATION_READY: { connect("confirmed", callable_mp(this, &PluginConfigDialog::_on_confirmed)); - get_cancel_button()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_cancelled)); + get_cancel_button()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_canceled)); } break; } } diff --git a/editor/plugin_config_dialog.h b/editor/plugin_config_dialog.h index e8df308c54..50b901a39e 100644 --- a/editor/plugin_config_dialog.h +++ b/editor/plugin_config_dialog.h @@ -58,7 +58,7 @@ class PluginConfigDialog : public ConfirmationDialog { void _clear_fields(); void _on_confirmed(); - void _on_cancelled(); + void _on_canceled(); void _on_language_changed(const int p_language); void _on_required_text_changed(const String &p_text); String _get_subfolder(); diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 7f8137f8d5..0daf934e17 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -74,7 +74,6 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) { } tool_create->set_disabled(read_only); - interpolation->set_disabled(read_only); max_x_value->set_editable(!read_only); min_x_value->set_editable(!read_only); max_y_value->set_editable(!read_only); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 14e3cb4b97..f5f9ec11b3 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -187,7 +187,7 @@ void AnimationNodeBlendTreeEditor::update_graph() { String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name; EditorProperty *prop = EditorInspector::instantiate_property_editor(tree, F.type, base_path, F.hint, F.hint_string, F.usage); if (prop) { - prop->set_read_only(read_only); + prop->set_read_only(read_only || (F.usage & PROPERTY_USAGE_READ_ONLY)); prop->set_object_and_property(tree, base_path); prop->update_property(); prop->set_name_split_ratio(0); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index d66982f31b..bf7e419fe4 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -554,7 +554,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int file_popup->add_separator(); file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_LIBRARY); Rect2 pos = tree->get_item_rect(p_item, 1, 0); - Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height); + Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height)); file_popup->popup(Rect2(popup_pos, Size2())); file_dialog_animation = StringName(); @@ -594,7 +594,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int file_popup->add_separator(); file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_ANIMATION); Rect2 pos = tree->get_item_rect(p_item, 1, 0); - Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height); + Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height)); file_popup->popup(Rect2(popup_pos, Size2())); file_dialog_animation = anim_name; diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index caee7514d0..06241d07cf 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -324,7 +324,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { void AnimationPlayerEditor::_animation_new() { int count = 1; - String base = TTR("New Anim"); + String base = "new_animation"; String current_library_name = ""; if (animation->has_selectable_items()) { String current_animation_name = animation->get_item_text(animation->get_selected()); @@ -337,7 +337,7 @@ void AnimationPlayerEditor::_animation_new() { while (true) { String attempt = base; if (count > 1) { - attempt += " (" + itos(count) + ")"; + attempt += vformat("_%d", count); } if (player->has_animation(attempt_prefix + attempt)) { count++; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index a675495429..c0972d201e 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1237,7 +1237,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { if (playback.is_valid()) { playing = playback->is_playing(); current = playback->get_current_node(); - blend_from = playback->get_blend_from_node(); + blend_from = playback->get_fading_from_node(); travel_path = playback->get_travel_path(); } @@ -1695,7 +1695,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { tp = playback->get_travel_path(); is_playing = playback->is_playing(); current_node = playback->get_current_node(); - blend_from_node = playback->get_blend_from_node(); + blend_from_node = playback->get_fading_from_node(); play_pos = playback->get_current_play_pos(); current_length = playback->get_current_length(); } diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 9f2cfc8d9c..2639765283 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -107,7 +107,7 @@ void EditorAssetLibraryItem::_bind_methods() { EditorAssetLibraryItem::EditorAssetLibraryItem() { Ref<StyleBoxEmpty> border; border.instantiate(); - border->set_default_margin_all(5 * EDSCALE); + border->set_content_margin_all(5 * EDSCALE); add_theme_style_override("panel", border); HBoxContainer *hb = memnew(HBoxContainer); @@ -705,6 +705,12 @@ const char *EditorAssetLibrary::support_key[SUPPORT_MAX] = { "testing", }; +const char *EditorAssetLibrary::support_text[SUPPORT_MAX] = { + TTRC("Official"), + TTRC("Community"), + TTRC("Testing"), +}; + void EditorAssetLibrary::_select_author(int p_id) { // Open author window. } @@ -1242,15 +1248,28 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const library_vb->add_child(asset_bottom_page); if (result.is_empty()) { + String support_list; + for (int i = 0; i < SUPPORT_MAX; i++) { + if (support->get_popup()->is_item_checked(i)) { + if (!support_list.is_empty()) { + support_list += ", "; + } + support_list += TTRGET(support_text[i]); + } + } + if (support_list.is_empty()) { + support_list = "-"; + } + if (!filter->get_text().is_empty()) { library_info->set_text( - vformat(TTR("No results for \"%s\"."), filter->get_text())); + vformat(TTR("No results for \"%s\" for support level(s): %s."), filter->get_text(), support_list)); } else { // No results, even though the user didn't search for anything specific. // This is typically because the version number changed recently // and no assets compatible with the new version have been published yet. library_info->set_text( - vformat(TTR("No results compatible with %s %s."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH))); + vformat(TTR("No results compatible with %s %s for support level(s): %s.\nCheck the enabled support levels using the 'Support' button in the top-right corner."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH), support_list)); } library_info->show(); } else { @@ -1510,9 +1529,9 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { search_hb2->add_child(support); support->set_text(TTR("Support")); support->get_popup()->set_hide_on_checkable_item_selection(false); - support->get_popup()->add_check_item(TTR("Official"), SUPPORT_OFFICIAL); - support->get_popup()->add_check_item(TTR("Community"), SUPPORT_COMMUNITY); - support->get_popup()->add_check_item(TTR("Testing"), SUPPORT_TESTING); + support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_OFFICIAL]), SUPPORT_OFFICIAL); + support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_COMMUNITY]), SUPPORT_COMMUNITY); + support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_TESTING]), SUPPORT_TESTING); support->get_popup()->set_item_checked(SUPPORT_OFFICIAL, true); support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, true); support->get_popup()->connect("id_pressed", callable_mp(this, &EditorAssetLibrary::_support_toggled)); @@ -1530,7 +1549,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { Ref<StyleBoxEmpty> border2; border2.instantiate(); - border2->set_default_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE); + border2->set_content_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE); PanelContainer *library_vb_border = memnew(PanelContainer); library_scroll->add_child(library_vb_border); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 0667f474da..8c74da0e2a 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -234,6 +234,7 @@ class EditorAssetLibrary : public PanelContainer { static const char *sort_key[SORT_MAX]; static const char *sort_text[SORT_MAX]; static const char *support_key[SUPPORT_MAX]; + static const char *support_text[SUPPORT_MAX]; ///MainListing diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp index 4f82aaf071..30fc60b0e0 100644 --- a/editor/plugins/bit_map_editor_plugin.cpp +++ b/editor/plugins/bit_map_editor_plugin.cpp @@ -53,7 +53,7 @@ BitMapEditor::BitMapEditor() { // Reduce extra padding on top and bottom of size label. Ref<StyleBoxEmpty> stylebox; stylebox.instantiate(); - stylebox->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); + stylebox->set_content_margin(SIDE_RIGHT, 4 * EDSCALE); size_label->add_theme_style_override("normal", stylebox); } diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index c913a9b0ab..3d94dd13a7 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -566,9 +566,9 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic if (hit_list.size() > 0) { shortest = hit_list[0]; - for (uint32_t i = 0; i < hit_list.size(); i++) { - if (hit_list[i].length() < shortest.length()) { - shortest = hit_list[i]; // Prioritize parent. + for (const String &hit : hit_list) { + if (hit.length() < shortest.length()) { + shortest = hit; // Prioritize parent. } } } @@ -592,9 +592,9 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic if (hit_list.size() > 0) { shortest = hit_list[0]; - for (uint32_t i = 0; i < hit_list.size(); i++) { - if (hit_list[i].length() <= shortest.length()) { - shortest = hit_list[i]; // Prioritize parent. + for (const String &hit : hit_list) { + if (hit.length() <= shortest.length()) { + shortest = hit; // Prioritize parent. } } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 4c14755b03..5d0555a10e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -246,7 +246,7 @@ public: } }; -bool CanvasItemEditor::_is_node_locked(const Node *p_node) { +bool CanvasItemEditor::_is_node_locked(const Node *p_node) const { return p_node->get_meta("_edit_lock_", false); } @@ -770,7 +770,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po return still_selected; } -List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) { +List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) const { List<CanvasItem *> selection; for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) { CanvasItem *ci = Object::cast_to<CanvasItem>(E.key); @@ -1226,7 +1226,6 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo bool panner_active = panner->gui_input(p_event, warped_panning ? viewport->get_global_rect() : Rect2()); if (panner->is_panning() != pan_pressed) { pan_pressed = panner->is_panning(); - _update_cursor(); } if (panner_active) { @@ -2570,8 +2569,10 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { // Handles the mouse hovering _gui_input_hover(p_event); - // Change the cursor - _update_cursor(); + if (mb.is_valid()) { + // Update the default cursor. + _update_cursor(); + } // Grab focus if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) { @@ -2580,6 +2581,31 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { } void CanvasItemEditor::_update_cursor() { + // Choose the correct default cursor. + CursorShape c = CURSOR_ARROW; + switch (tool) { + case TOOL_MOVE: + c = CURSOR_MOVE; + break; + case TOOL_EDIT_PIVOT: + c = CURSOR_CROSS; + break; + case TOOL_PAN: + c = CURSOR_DRAG; + break; + case TOOL_RULER: + c = CURSOR_CROSS; + break; + default: + break; + } + if (pan_pressed) { + c = CURSOR_DRAG; + } + set_default_cursor_shape(c); +} + +Control::CursorShape CanvasItemEditor::get_cursor_shape(const Point2 &p_pos) const { // Compute an eventual rotation of the cursor const CursorShape rotation_array[4] = { CURSOR_HSIZE, CURSOR_BDIAGSIZE, CURSOR_VSIZE, CURSOR_FDIAGSIZE }; int rotation_array_index = 0; @@ -2601,26 +2627,8 @@ void CanvasItemEditor::_update_cursor() { } // Choose the correct cursor - CursorShape c = CURSOR_ARROW; + CursorShape c = get_default_cursor_shape(); switch (drag_type) { - case DRAG_NONE: - switch (tool) { - case TOOL_MOVE: - c = CURSOR_MOVE; - break; - case TOOL_EDIT_PIVOT: - c = CURSOR_CROSS; - break; - case TOOL_PAN: - c = CURSOR_DRAG; - break; - case TOOL_RULER: - c = CURSOR_CROSS; - break; - default: - break; - } - break; case DRAG_LEFT: case DRAG_RIGHT: c = rotation_array[rotation_array_index]; @@ -2662,16 +2670,7 @@ void CanvasItemEditor::_update_cursor() { if (pan_pressed) { c = CURSOR_DRAG; } - - if (c != viewport->get_default_cursor_shape()) { - viewport->set_default_cursor_shape(c); - - // Force refresh cursor if it's over the viewport. - if (viewport->get_global_rect().has_point(get_global_mouse_position())) { - DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)viewport->get_default_cursor_shape(); - DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape); - } - } + return c; } void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Side p_side) { @@ -3958,8 +3957,8 @@ void CanvasItemEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons"))); - select_sb->set_margin_size_all(4); - select_sb->set_default_margin_all(4); + select_sb->set_texture_margin_all(4); + select_sb->set_content_margin_all(4); AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed)); _keying_changed(); @@ -3990,6 +3989,10 @@ void CanvasItemEditor::_selection_changed() { } void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { + if (!p_canvas_item) { + return; + } + Array selection = editor_selection->get_selected_nodes(); if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) { _reset_drag(); @@ -5925,7 +5928,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it EditorNode::get_singleton()->get_gui_base()->add_child(selector); selector->set_title(TTR("Change Default Type")); selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed)); - selector->connect("cancelled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed)); + selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed)); VBoxContainer *vbc = memnew(VBoxContainer); selector->add_child(vbc); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index f4fcc8a3d2..1e01eac82d 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -368,7 +368,7 @@ private: void _pan_callback(Vector2 p_scroll_vec); void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); - bool _is_node_locked(const Node *p_node); + bool _is_node_locked(const Node *p_node) const; bool _is_node_movable(const Node *p_node, bool p_popup_warning = false); void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false); @@ -402,7 +402,7 @@ private: void _prepare_grid_menu(); void _on_grid_menu_id_pressed(int p_id); - List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true); + List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true) const; Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true); Rect2 _get_encompassing_rect(const Node *p_node); @@ -552,6 +552,8 @@ public: void focus_selection(); void center_at(const Point2 &p_pos); + virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override; + EditorSelection *editor_selection = nullptr; CanvasItemEditor(); diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp index 3676c2c222..2eb17b3f13 100644 --- a/editor/plugins/gradient_editor.cpp +++ b/editor/plugins/gradient_editor.cpp @@ -52,12 +52,12 @@ void GradientEditor::reverse_gradient() { int GradientEditor::_get_point_from_pos(int x) { int result = -1; - int total_w = get_size().width - get_size().height - draw_spacing; + int total_w = get_size().width - get_size().height - draw_spacing - handle_width; float min_distance = 1e20; for (int i = 0; i < points.size(); i++) { // Check if we clicked at point. float distance = ABS(x - points[i].offset * total_w); - float min = (handle_width / 2 * 1.7); // Make it easier to grab. + float min = handle_width * 0.85; // Allow the mouse to be more than half a handle width away for ease of grabbing. if (distance <= min && distance < min_distance) { result = i; min_distance = distance; @@ -198,116 +198,87 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseButton> mb = p_event; - // Show color picker on double click. - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) { - grabbed = _get_point_from_pos(mb->get_position().x); - _show_color_picker(); - accept_event(); - return; - } - - // Delete point on right click. - if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { - grabbed = _get_point_from_pos(mb->get_position().x); - if (grabbed != -1) { - points.remove_at(grabbed); - grabbed = -1; - grabbing = false; - queue_redraw(); - emit_signal(SNAME("ramp_changed")); - accept_event(); - } - } - - // Hold alt key to duplicate selected color. - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && mb->is_alt_pressed()) { - int x = mb->get_position().x; - grabbed = _get_point_from_pos(x); - if (grabbed != -1) { - int total_w = get_size().width - get_size().height - draw_spacing; - Gradient::Point new_point = points[grabbed]; - new_point.offset = CLAMP(x / float(total_w), 0, 1); + if (mb.is_valid() && mb->is_pressed()) { + float adjusted_mb_x = mb->get_position().x - handle_width / 2; - points.push_back(new_point); - points.sort(); - for (int i = 0; i < points.size(); ++i) { - if (points[i].offset == new_point.offset) { - grabbed = i; - break; - } + // Delete point on right click. + if (mb->get_button_index() == MouseButton::RIGHT) { + grabbed = _get_point_from_pos(adjusted_mb_x); + if (grabbed != -1) { + points.remove_at(grabbed); + grabbed = -1; + grabbing = false; + queue_redraw(); + emit_signal(SNAME("ramp_changed")); + accept_event(); } - - emit_signal(SNAME("ramp_changed")); - queue_redraw(); } - } - // Select. - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { - queue_redraw(); - int x = mb->get_position().x; - int total_w = get_size().width - get_size().height - draw_spacing; + // Hold Alt key to duplicate selected color. + if (mb->get_button_index() == MouseButton::LEFT && mb->is_alt_pressed()) { + grabbed = _get_point_from_pos(adjusted_mb_x); - //Check if color selector was clicked. - if (x > total_w + draw_spacing) { - _show_color_picker(); - return; - } - - grabbing = true; + if (grabbed != -1) { + int total_w = get_size().width - get_size().height - draw_spacing - handle_width; + Gradient::Point new_point = points[grabbed]; + new_point.offset = CLAMP(adjusted_mb_x / float(total_w), 0, 1); + points.push_back(new_point); + points.sort(); + for (int i = 0; i < points.size(); ++i) { + if (points[i].offset == new_point.offset) { + grabbed = i; + break; + } + } - grabbed = _get_point_from_pos(x); - //grab or select - if (grabbed != -1) { - return; + emit_signal(SNAME("ramp_changed")); + queue_redraw(); + } } - // Insert point. - Gradient::Point new_point; - new_point.offset = CLAMP(x / float(total_w), 0, 1); - - Gradient::Point prev; - Gradient::Point next; + // Select. + if (mb->get_button_index() == MouseButton::LEFT) { + queue_redraw(); + int total_w = get_size().width - get_size().height - draw_spacing - handle_width; - int pos = -1; - for (int i = 0; i < points.size(); i++) { - if (points[i].offset < new_point.offset) { - pos = i; + // Check if color selector was clicked or ramp was double-clicked. + if (adjusted_mb_x > total_w + draw_spacing) { + if (!mb->is_double_click()) { + _show_color_picker(); + } + return; + } else if (mb->is_double_click()) { + grabbed = _get_point_from_pos(adjusted_mb_x); + _show_color_picker(); + accept_event(); + return; } - } - if (pos == -1) { - prev.color = Color(0, 0, 0); - prev.offset = 0; - if (points.size()) { - next = points[0]; - } else { - next.color = Color(1, 1, 1); - next.offset = 1.0; - } - } else { - if (pos == points.size() - 1) { - next.color = Color(1, 1, 1); - next.offset = 1.0; - } else { - next = points[pos + 1]; + grabbing = true; + grabbed = _get_point_from_pos(adjusted_mb_x); + + // Grab or select. + if (grabbed != -1) { + return; } - prev = points[pos]; - } - new_point.color = prev.color.lerp(next.color, (new_point.offset - prev.offset) / (next.offset - prev.offset)); + // Insert point. + Gradient::Point new_point; + new_point.offset = CLAMP(adjusted_mb_x / float(total_w), 0, 1); + new_point.color = gradient->get_color_at_offset(new_point.offset); - points.push_back(new_point); - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == new_point.offset) { - grabbed = i; - break; + points.push_back(new_point); + points.sort(); + for (int i = 0; i < points.size(); i++) { + if (points[i].offset == new_point.offset) { + grabbed = i; + break; + } } - } - emit_signal(SNAME("ramp_changed")); + emit_signal(SNAME("ramp_changed")); + } } if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) { @@ -321,18 +292,16 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && grabbing) { - int total_w = get_size().width - get_size().height - draw_spacing; - - int x = mm->get_position().x; - - float newofs = CLAMP(x / float(total_w), 0, 1); + float adjusted_mm_x = mm->get_position().x - handle_width / 2; + int total_w = get_size().width - get_size().height - draw_spacing - handle_width; + float newofs = CLAMP(adjusted_mm_x / float(total_w), 0, 1); // Snap to "round" coordinates if holding Ctrl. // Be more precise if holding Shift as well. if (mm->is_ctrl_pressed()) { newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1); } else if (mm->is_shift_pressed()) { - // Snap to nearest point if holding just Shift + // Snap to nearest point if holding just Shift. const float snap_threshold = 0.03; float smallest_ofs = snap_threshold; bool found = false; @@ -421,7 +390,7 @@ void GradientEditor::_notification(int p_what) { // Draw borders around color ramp if in focus. if (has_focus()) { - draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false); + draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false, 1); } // Draw point markers. @@ -432,18 +401,18 @@ void GradientEditor::_notification(int p_what) { draw_line(Vector2(points[i].offset * total_w + handle_width / 2, 0), Vector2(points[i].offset * total_w + handle_width / 2, h / 2), col); Rect2 rect = Rect2(points[i].offset * total_w, h / 2, handle_width, h / 2); draw_rect(rect, points[i].color, true); - draw_rect(rect, col, false); + draw_rect(rect, col, false, 1); if (grabbed == i) { const Color focus_color = get_theme_color(SNAME("accent_color"), SNAME("Editor")); rect = rect.grow(-1); if (has_focus()) { - draw_rect(rect, focus_color, false); + draw_rect(rect, focus_color, false, 1); } else { - draw_rect(rect, focus_color.darkened(0.4), false); + draw_rect(rect, focus_color.darkened(0.4), false, 1); } rect = rect.grow(-1); - draw_rect(rect, col, false); + draw_rect(rect, col, false, 1); } } @@ -454,7 +423,7 @@ void GradientEditor::_notification(int p_what) { // Draw with selection color. draw_rect(Rect2(button_offset, 0, h, h), points[grabbed].color); } else { - // If no color selected draw grey color with 'X' on top. + // If no color selected draw gray color with 'X' on top. draw_rect(Rect2(button_offset, 0, h, h), Color(0.5, 0.5, 0.5, 1)); draw_line(Vector2(button_offset, 0), Vector2(button_offset + h, h), Color(1, 1, 1, 0.6)); draw_line(Vector2(button_offset, h), Vector2(button_offset + h, 0), Color(1, 1, 1, 0.6)); diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index 1adcc2a3b4..519cfcaa94 100644 --- a/editor/plugins/lightmap_gi_editor_plugin.cpp +++ b/editor/plugins/lightmap_gi_editor_plugin.cpp @@ -35,12 +35,43 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) { if (lightmap) { - LightmapGI::BakeError err; + LightmapGI::BakeError err = LightmapGI::BAKE_ERROR_OK; const uint64_t time_started = OS::get_singleton()->get_ticks_msec(); - if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) { - err = lightmap->bake(lightmap, p_file, bake_func_step); + if (get_tree()->get_edited_scene_root()) { + Ref<LightmapGIData> lightmapGIData = lightmap->get_light_data(); + + if (lightmapGIData.is_valid()) { + String path = lightmapGIData->get_path(); + if (!path.is_resource_file()) { + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + err = LightmapGI::BAKE_ERROR_FOREIGN_DATA; + } + } else { + if (FileAccess::exists(base + ".import")) { + err = LightmapGI::BAKE_ERROR_FOREIGN_DATA; + } + } + } + } else { + if (FileAccess::exists(path + ".import")) { + err = LightmapGI::BAKE_ERROR_FOREIGN_DATA; + } + } + } + + if (err == LightmapGI::BAKE_ERROR_OK) { + if (get_tree()->get_edited_scene_root() == lightmap) { + err = lightmap->bake(lightmap, p_file, bake_func_step); + } else { + err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step); + } + } } else { - err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step); + err = LightmapGI::BAKE_ERROR_NO_SCENE_ROOT; } bake_func_end(time_started); @@ -59,16 +90,21 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) { file_dialog->set_current_path(scene_path); file_dialog->popup_file_dialog(); - } break; - case LightmapGI::BAKE_ERROR_NO_MESHES: + case LightmapGI::BAKE_ERROR_NO_MESHES: { EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on.")); - break; - case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: + } break; + case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: { EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable.")); - break; + } break; + case LightmapGI::BAKE_ERROR_NO_SCENE_ROOT: { + EditorNode::get_singleton()->show_warning(TTR("No editor scene root found.")); + } break; + case LightmapGI::BAKE_ERROR_FOREIGN_DATA: { + EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene.")); + } break; default: { - } + } break; } } } diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 35b7367393..e8976667dd 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -460,7 +460,7 @@ void MeshInstance3DEditor::_debug_uv_draw() { debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), get_theme_color(SNAME("dark_color_3"), SNAME("Editor"))); debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size()); // Use a translucent color to allow overlapping triangles to be visible. - debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5), Math::round(EDSCALE)); + debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5)); } void MeshInstance3DEditor::_create_outline_mesh() { diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 9198ebeca8..f1b7ed73b8 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2208,11 +2208,6 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) { _menu_option(VIEW_CENTER_TO_SELECTION); } - // Orthgonal mode doesn't work in freelook. - if (!freelook_active && ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) { - _menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL); - _update_name(); - } if (ED_IS_SHORTCUT("spatial_editor/align_transform_with_view", p_event)) { _menu_option(VIEW_ALIGN_TRANSFORM_WITH_VIEW); } @@ -3279,6 +3274,10 @@ void Node3DEditorViewport::_menu_option(int p_option) { _update_name(); } break; + case VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL: { + _menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL); + + } break; case VIEW_AUTO_ORTHOGONAL: { int idx = view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL); bool current = view_menu->get_popup()->is_item_checked(idx); @@ -3894,8 +3893,6 @@ Dictionary Node3DEditorViewport::get_state() const { void Node3DEditorViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred. - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &Node3DEditorViewport::drop_data_fw); ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport"))); ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport"))); @@ -4921,7 +4918,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p c->add_child(viewport); surface = memnew(Control); - surface->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CD(surface, Node3DEditorViewport); add_child(surface); surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); surface->set_clip_contents(true); @@ -4954,8 +4951,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR); view_menu->get_popup()->add_separator(); - view_menu->get_popup()->add_radio_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE); - view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL); + view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal"), VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL); + view_menu->get_popup()->add_radio_check_item(TTR("Perspective"), VIEW_PERSPECTIVE); + view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal"), VIEW_ORTHOGONAL); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true); view_menu->get_popup()->add_check_item(TTR("Auto Orthogonal Enabled"), VIEW_AUTO_ORTHOGONAL); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), true); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index edc09f115a..a1fd9757d0 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -117,6 +117,7 @@ class Node3DEditorViewport : public Control { VIEW_PERSPECTIVE, VIEW_ENVIRONMENT, VIEW_ORTHOGONAL, + VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL, VIEW_HALF_RESOLUTION, VIEW_AUDIO_LISTENER, VIEW_AUDIO_DOPPLER, diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 05fc464226..c30f0ec62d 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -1254,7 +1254,7 @@ Polygon2DEditor::Polygon2DEditor() { uv_edit = memnew(AcceptDialog); add_child(uv_edit); uv_edit->set_title(TTR("Polygon 2D UV Editor")); - uv_edit->connect("cancelled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide)); + uv_edit->connect("canceled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide)); VBoxContainer *uv_main_vb = memnew(VBoxContainer); uv_edit->add_child(uv_main_vb); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 250f1403af..dcbff2c756 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -342,10 +342,6 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant void ResourcePreloaderEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library); ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource); - - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw); } ResourcePreloaderEditor::ResourcePreloaderEditor() { @@ -379,7 +375,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { tree->set_column_expand(1, true); tree->set_v_size_flags(SIZE_EXPAND_FILL); - tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(tree, ResourcePreloaderEditor); vbc->add_child(tree); dialog = memnew(AcceptDialog); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 4268abe4a2..e515b46b1e 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2174,6 +2174,8 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p p_text_file->set_last_modified_time(FileAccess::get_modified_time(p_path)); } + EditorFileSystem::get_singleton()->update_file(p_path); + _res_saved_callback(sqscr); return OK; } @@ -2256,11 +2258,14 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col, args.push_back(script_path); } - Error err = OS::get_singleton()->create_process(path, args); - if (err == OK) { - return false; + if (!path.is_empty()) { + Error err = OS::get_singleton()->create_process(path, args); + if (err == OK) { + return false; + } } - WARN_PRINT("Couldn't open external text editor, using internal"); + + ERR_PRINT("Couldn't open external text editor, falling back to the internal editor. Review your `text_editor/external/` editor settings."); } for (int i = 0; i < tab_container->get_tab_count(); i++) { @@ -2489,7 +2494,6 @@ void ScriptEditor::save_all_scripts() { } _update_script_names(); - EditorFileSystem::get_singleton()->update_script_classes(); } void ScriptEditor::apply_scripts() const { @@ -3612,10 +3616,6 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("register_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::register_syntax_highlighter); ClassDB::bind_method(D_METHOD("unregister_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::unregister_syntax_highlighter); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw); - ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2); ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script); ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); @@ -3671,7 +3671,7 @@ ScriptEditor::ScriptEditor() { _sort_list_on_update = true; script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED); script_list->set_allow_rmb_select(true); - script_list->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(script_list, ScriptEditor); context_menu = memnew(PopupMenu); add_child(context_menu); @@ -4007,12 +4007,6 @@ void ScriptEditorPlugin::apply_changes() { script_editor->apply_scripts(); } -void ScriptEditorPlugin::restore_global_state() { -} - -void ScriptEditorPlugin::save_global_state() { -} - void ScriptEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { script_editor->set_window_layout(p_layout); } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index d4c80c416b..988d07621c 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -542,9 +542,6 @@ public: virtual void save_external_data() override; virtual void apply_changes() override; - virtual void restore_global_state() override; - virtual void save_global_state() override; - virtual void set_window_layout(Ref<ConfigFile> p_layout) override; virtual void get_window_layout(Ref<ConfigFile> p_layout) override; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 4d525cc5a9..b719a2ce30 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1490,14 +1490,6 @@ void ScriptTextEditor::_notification(int p_what) { } } -void ScriptTextEditor::_bind_methods() { - ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods); - - ClassDB::bind_method("_get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); - ClassDB::bind_method("_can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &ScriptTextEditor::drop_data_fw); -} - Control *ScriptTextEditor::get_edit_menu() { return edit_hb; } @@ -2167,7 +2159,7 @@ ScriptTextEditor::ScriptTextEditor() { connection_info_dialog = memnew(ConnectionInfoDialog); - code_editor->get_text_editor()->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(code_editor->get_text_editor(), ScriptTextEditor); } ScriptTextEditor::~ScriptTextEditor() { diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 9db0191128..1d96376748 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -176,7 +176,6 @@ protected: void _warning_clicked(Variant p_line); void _notification(int p_what); - static void _bind_methods(); HashMap<String, Ref<EditorSyntaxHighlighter>> highlighters; void _change_syntax_highlighter(int p_idx); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 709ca30858..907bc81674 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -43,10 +43,10 @@ void ShaderEditorPlugin::_update_shader_list() { shader_list->clear(); - for (uint32_t i = 0; i < edited_shaders.size(); i++) { - Ref<Resource> shader = edited_shaders[i].shader; + for (EditedShader &edited_shader : edited_shaders) { + Ref<Resource> shader = edited_shader.shader; if (shader.is_null()) { - shader = edited_shaders[i].shader_inc; + shader = edited_shader.shader_inc; } String path = shader->get_path(); @@ -62,8 +62,8 @@ void ShaderEditorPlugin::_update_shader_list() { } bool unsaved = false; - if (edited_shaders[i].shader_editor) { - unsaved = edited_shaders[i].shader_editor->is_unsaved(); + if (edited_shader.shader_editor) { + unsaved = edited_shader.shader_editor->is_unsaved(); } // TODO: Handle visual shaders too. @@ -86,7 +86,7 @@ void ShaderEditorPlugin::_update_shader_list() { } for (int i = FILE_SAVE; i < FILE_MAX; i++) { - file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(i), edited_shaders.size() == 0); + file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(i), edited_shaders.is_empty()); } _update_shader_list_status(); @@ -117,6 +117,10 @@ void ShaderEditorPlugin::_move_shader_tab(int p_from, int p_to) { } void ShaderEditorPlugin::edit(Object *p_object) { + if (!p_object) { + return; + } + EditedShader es; ShaderInclude *si = Object::cast_to<ShaderInclude>(p_object); @@ -175,36 +179,36 @@ void ShaderEditorPlugin::selected_notify() { } TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref<Shader> &p_for_shader) { - for (uint32_t i = 0; i < edited_shaders.size(); i++) { - if (edited_shaders[i].shader == p_for_shader) { - return edited_shaders[i].shader_editor; + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader == p_for_shader) { + return edited_shader.shader_editor; } } return nullptr; } VisualShaderEditor *ShaderEditorPlugin::get_visual_shader_editor(const Ref<Shader> &p_for_shader) { - for (uint32_t i = 0; i < edited_shaders.size(); i++) { - if (edited_shaders[i].shader == p_for_shader) { - return edited_shaders[i].visual_shader_editor; + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader == p_for_shader) { + return edited_shader.visual_shader_editor; } } return nullptr; } void ShaderEditorPlugin::save_external_data() { - for (uint32_t i = 0; i < edited_shaders.size(); i++) { - if (edited_shaders[i].shader_editor) { - edited_shaders[i].shader_editor->save_external_data(); + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader_editor) { + edited_shader.shader_editor->save_external_data(); } } _update_shader_list(); } void ShaderEditorPlugin::apply_changes() { - for (uint32_t i = 0; i < edited_shaders.size(); i++) { - if (edited_shaders[i].shader_editor) { - edited_shaders[i].shader_editor->apply_shaders(); + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader_editor) { + edited_shader.shader_editor->apply_shaders(); } } } @@ -234,8 +238,8 @@ void ShaderEditorPlugin::_close_shader(int p_index) { void ShaderEditorPlugin::_resource_saved(Object *obj) { // May have been renamed on save. - for (uint32_t i = 0; i < edited_shaders.size(); i++) { - if (edited_shaders[i].shader.ptr() == obj) { + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader.ptr() == obj) { _update_shader_list(); return; } @@ -413,12 +417,6 @@ void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_da } } -void ShaderEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ShaderEditorPlugin::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::drop_data_fw); -} - ShaderEditorPlugin::ShaderEditorPlugin() { main_split = memnew(HSplitContainer); @@ -451,7 +449,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() { vb->add_child(shader_list); shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected)); shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked)); - shader_list->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(shader_list, ShaderEditorPlugin); main_split->add_child(vb); vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 8ca4a534ab..408d08ade0 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -92,9 +92,6 @@ class ShaderEditorPlugin : public EditorPlugin { bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); -protected: - static void _bind_methods(); - public: virtual String get_name() const override { return "Shader"; } virtual void edit(Object *p_object) override; diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 53486d9509..3ee9823f3a 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -813,7 +813,7 @@ void Skeleton3DEditor::create_editors() { joint_tree->set_v_size_flags(SIZE_EXPAND_FILL); joint_tree->set_h_size_flags(SIZE_EXPAND_FILL); joint_tree->set_allow_rmb_select(true); - joint_tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(joint_tree, Skeleton3DEditor); s_con->add_child(joint_tree); pose_editor = memnew(BoneTransformEditor(skeleton)); @@ -889,10 +889,6 @@ void Skeleton3DEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties); ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &Skeleton3DEditor::_on_click_skeleton_option); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw); - ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone); ClassDB::bind_method(D_METHOD("_draw_gizmo"), &Skeleton3DEditor::_draw_gizmo); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index d5365068c3..74c9286325 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -788,11 +788,11 @@ void SpriteFramesEditor::_animation_name_edited() { } void SpriteFramesEditor::_animation_add() { - String name = "New Anim"; + String name = "new_animation"; int counter = 0; while (frames->has_animation(name)) { counter++; - name = "New Anim " + itos(counter); + name = vformat("new_animation_%d", counter); } List<Node *> nodes; @@ -1247,9 +1247,6 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da void SpriteFramesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SpriteFramesEditor::drop_data_fw); } SpriteFramesEditor::SpriteFramesEditor() { @@ -1408,7 +1405,7 @@ SpriteFramesEditor::SpriteFramesEditor() { frame_list->set_max_columns(0); frame_list->set_icon_mode(ItemList::ICON_MODE_TOP); frame_list->set_max_text_lines(2); - frame_list->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(frame_list, SpriteFramesEditor); frame_list->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_frame_list_gui_input)); frame_list->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected)); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index ad5881c76f..a376699e54 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -649,8 +649,6 @@ TextEditor::TextEditor() { goto_line_dialog = memnew(GotoLineDialog); add_child(goto_line_dialog); - - code_editor->get_text_editor()->set_drag_forwarding_compat(this); } TextEditor::~TextEditor() { diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 9bad2f2fbf..d7559bc18e 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -256,10 +256,10 @@ void TextureRegionEditor::_region_draw() { margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); } else if (obj_styleBox.is_valid()) { - margins[0] = obj_styleBox->get_margin_size(SIDE_TOP); - margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM); - margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT); - margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT); + margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP); + margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM); + margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT); + margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT); } Vector2 pos[4] = { @@ -314,10 +314,10 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); } else if (obj_styleBox.is_valid()) { - margins[0] = obj_styleBox->get_margin_size(SIDE_TOP); - margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM); - margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT); - margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT); + margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP); + margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM); + margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT); + margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT); } Vector2 pos[4] = { @@ -431,8 +431,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { undo_redo->add_do_method(node_ninepatch, "set_patch_margin", side[edited_margin], node_ninepatch->get_patch_margin(side[edited_margin])); undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", side[edited_margin], prev_margin); } else if (obj_styleBox.is_valid()) { - undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], obj_styleBox->get_margin_size(side[edited_margin])); - undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], prev_margin); + undo_redo->add_do_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], obj_styleBox->get_texture_margin(side[edited_margin])); + undo_redo->add_undo_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], prev_margin); obj_styleBox->emit_signal(CoreStringNames::get_singleton()->changed); } edited_margin = -1; @@ -474,7 +474,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { node_ninepatch->set_patch_margin(side[edited_margin], prev_margin); } if (obj_styleBox.is_valid()) { - obj_styleBox->set_margin_size(side[edited_margin], prev_margin); + obj_styleBox->set_texture_margin(side[edited_margin], prev_margin); } edited_margin = -1; } else { @@ -535,7 +535,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { node_ninepatch->set_patch_margin(side[edited_margin], new_margin); } if (obj_styleBox.is_valid()) { - obj_styleBox->set_margin_size(side[edited_margin], new_margin); + obj_styleBox->set_texture_margin(side[edited_margin], new_margin); } } else { Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position()); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 40aac77a99..14ff59b442 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -3335,8 +3335,10 @@ void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) { } edited_theme = p_theme; - edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced)); - _update_type_list(); + if (edited_theme.is_valid()) { + edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced)); + _update_type_list(); + } add_type_dialog->set_edited_theme(edited_theme); } @@ -3496,7 +3498,9 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) { preview_tab->set_preview_theme(p_theme); } - theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file()); + if (theme.is_valid()) { + theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file()); + } } Ref<Theme> ThemeEditor::get_edited_theme() { diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 3c6ed0f049..0ac375407c 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -454,21 +454,31 @@ void TileAtlasView::set_padding(Side p_side, int p_padding) { margin_container_paddings[p_side] = p_padding; } -Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos) const { +Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp) const { Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); - if (texture.is_valid()) { - Vector2i margins = tile_set_atlas_source->get_margins(); - Vector2i separation = tile_set_atlas_source->get_separation(); - Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size(); + if (!texture.is_valid()) { + return TileSetSource::INVALID_ATLAS_COORDS; + } + + Vector2i margins = tile_set_atlas_source->get_margins(); + Vector2i separation = tile_set_atlas_source->get_separation(); + Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size(); - // Compute index in atlas - Vector2 pos = p_pos - margins; - Vector2i ret = (pos / (texture_region_size + separation)).floor(); + // Compute index in atlas + Vector2 pos = p_pos - margins; + Vector2i ret = (pos / (texture_region_size + separation)).floor(); - return ret; + // Return invalid value (without clamp). + Rect2i rect = Rect2(Vector2i(), tile_set_atlas_source->get_atlas_grid_size()); + if (!p_clamp && !rect.has_point(ret)) { + return TileSetSource::INVALID_ATLAS_COORDS; } - return TileSetSource::INVALID_ATLAS_COORDS; + // Clamp. + ret.x = CLAMP(ret.x, 0, rect.size.x - 1); + ret.y = CLAMP(ret.y, 0, rect.size.y - 1); + + return ret; } void TileAtlasView::_update_alternative_tiles_rect_cache() { diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h index 166abca2a3..f719bee704 100644 --- a/editor/plugins/tiles/tile_atlas_view.h +++ b/editor/plugins/tiles/tile_atlas_view.h @@ -128,7 +128,7 @@ public: void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); }; void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); }; - Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos) const; + Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp = false) const; void add_control_over_atlas_tiles(Control *p_control, bool scaled = true) { if (scaled) { diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 966d394ca1..1a4223e9e6 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -169,8 +169,7 @@ void GenericTilePolygonEditor::_base_control_draw() { } // Draw the polygons. - for (unsigned int i = 0; i < polygons.size(); i++) { - const Vector<Vector2> &polygon = polygons[i]; + for (const Vector<Vector2> &polygon : polygons) { Color color = polygon_color; if (!in_creation_polygon.is_empty()) { color = color.darkened(0.3); @@ -285,8 +284,8 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); undo_redo->add_undo_method(this, "clear_polygons"); - for (unsigned int i = 0; i < polygons.size(); i++) { - undo_redo->add_undo_method(this, "add_polygon", polygons[i]); + for (const PackedVector2Array &poly : polygons) { + undo_redo->add_undo_method(this, "add_polygon", poly); } undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); @@ -298,8 +297,8 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); undo_redo->add_undo_method(this, "clear_polygons"); - for (unsigned int i = 0; i < polygons.size(); i++) { - undo_redo->add_undo_method(this, "add_polygon", polygons[i]); + for (const PackedVector2Array &polygon : polygons) { + undo_redo->add_undo_method(this, "add_polygon", polygon); } undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); @@ -327,8 +326,8 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { } for (unsigned int i = 0; i < polygons.size(); i++) { Vector<Point2> new_polygon; - for (int point_index = 0; point_index < polygons[i].size(); point_index++) { - Vector2 point = polygons[i][point_index]; + for (const Vector2 &vec : polygons[i]) { + Vector2 point = vec; switch (p_item_pressed) { case ROTATE_RIGHT: { point = Vector2(-point.y, point.x); @@ -351,8 +350,8 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { } undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); - for (unsigned int i = 0; i < polygons.size(); i++) { - undo_redo->add_undo_method(this, "set_polygon", polygons[i]); + for (const PackedVector2Array &polygon : polygons) { + undo_redo->add_undo_method(this, "set_polygon", polygon); } undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); @@ -497,11 +496,11 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_ctrl_pressed()) { + if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_command_or_control_pressed()) { editor_zoom_widget->set_zoom_by_increments(1); _zoom_changed(); accept_event(); - } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_ctrl_pressed()) { + } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_command_or_control_pressed()) { editor_zoom_widget->set_zoom_by_increments(-1); _zoom_changed(); accept_event(); @@ -926,8 +925,8 @@ void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_ p_canvas_item->draw_set_transform_matrix(p_transform); Rect2i rect; - rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); - rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()))); + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true)); rect = rect.abs(); RBSet<TileMapCell> edited; @@ -961,7 +960,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { if (drag_type == DRAG_TYPE_PAINT) { - Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position())); + Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); for (int i = 0; i < line.size(); i++) { Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { @@ -984,14 +983,14 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::LEFT) { if (mb->is_pressed()) { - if (picker_button->is_pressed()) { - Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); + if (picker_button->is_pressed() || (mb->is_command_or_control_pressed() && !mb->is_shift_pressed())) { + Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true); coords = p_tile_set_atlas_source->get_tile_at_coords(coords); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { _set_painted_value(p_tile_set_atlas_source, coords, 0); picker_button->set_pressed(false); } - } else if (mb->is_ctrl_pressed()) { + } else if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) { drag_type = DRAG_TYPE_PAINT_RECT; drag_modified.clear(); drag_painted_value = _get_painted_value(); @@ -1000,7 +999,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti drag_type = DRAG_TYPE_PAINT; drag_modified.clear(); drag_painted_value = _get_painted_value(); - Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); + Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true); coords = p_tile_set_atlas_source->get_tile_at_coords(coords); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { TileMapCell cell; @@ -1015,8 +1014,8 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti } else { if (drag_type == DRAG_TYPE_PAINT_RECT) { Rect2i rect; - rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); - rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position())); + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true)); rect = rect.abs(); drag_modified.clear(); @@ -1532,26 +1531,32 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas } void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { - Array new_array = p_new_value; + Dictionary new_dict = p_new_value; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (KeyValue<TileMapCell, Variant> &E : p_previous_values) { - Array old_array = E.value; - Vector2i coords = E.key.get_atlas_coords(); - undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_array.size()); - for (int i = 0; i < old_array.size(); i++) { - Dictionary dict = old_array[i]; - undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["points"]); - undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way"]); - undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way_margin"]); + + Dictionary old_dict = E.value; + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/linear_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_dict["linear_velocity"]); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/angular_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_dict["angular_velocity"]); + Array old_polygon_array = old_dict["polygons"]; + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_polygon_array.size()); + for (int i = 0; i < old_polygon_array.size(); i++) { + Dictionary polygon_dict = old_polygon_array[i]; + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["points"]); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way"]); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way_margin"]); } - undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_array.size()); - for (int i = 0; i < new_array.size(); i++) { - Dictionary dict = new_array[i]; - undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["points"]); - undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way"]); - undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way_margin"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/linear_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_dict["linear_velocity"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/angular_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_dict["angular_velocity"]); + Array new_polygon_array = new_dict["polygons"]; + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_polygon_array.size()); + for (int i = 0; i < new_polygon_array.size(); i++) { + Dictionary polygon_dict = new_polygon_array[i]; + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["points"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way_margin"]); } } } @@ -1812,8 +1817,8 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas p_canvas_item->draw_set_transform_matrix(p_transform); Rect2i rect; - rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); - rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()))); + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true)); rect = rect.abs(); RBSet<TileMapCell> edited; @@ -1842,8 +1847,8 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas int terrain_set = int(painted["terrain_set"]); Rect2i rect; - rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); - rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()))); + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true)); rect = rect.abs(); RBSet<TileMapCell> edited; @@ -2003,7 +2008,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { - Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position())); + Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); for (int i = 0; i < line.size(); i++) { Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { @@ -2037,7 +2042,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) { int terrain_set = Dictionary(drag_painted_value)["terrain_set"]; int terrain = Dictionary(drag_painted_value)["terrain"]; - Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position())); + Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); for (int i = 0; i < line.size(); i++) { Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { @@ -2091,7 +2096,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) { if (mb->is_pressed()) { - if (mb->get_button_index() == MouseButton::LEFT && picker_button->is_pressed()) { + if (picker_button->is_pressed() || (mb->is_command_or_control_pressed() && !mb->is_shift_pressed())) { Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); coords = p_tile_set_atlas_source->get_tile_at_coords(coords); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { @@ -2134,7 +2139,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t if (mb->get_button_index() == MouseButton::RIGHT) { terrain_set = -1; } - if (mb->is_ctrl_pressed()) { + if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) { // Paint terrain set with rect. drag_type = DRAG_TYPE_PAINT_TERRAIN_SET_RECT; drag_modified.clear(); @@ -2175,7 +2180,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t if (mb->get_button_index() == MouseButton::RIGHT) { terrain = -1; } - if (mb->is_ctrl_pressed()) { + if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) { // Paint terrain bits with rect. drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS_RECT; drag_modified.clear(); @@ -2238,8 +2243,8 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) { Rect2i rect; - rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); - rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position())); + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true)); rect = rect.abs(); RBSet<TileMapCell> edited; @@ -2326,8 +2331,8 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t int terrain = int(painted["terrain"]); Rect2i rect; - rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); - rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position())); + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true)); rect = rect.abs(); RBSet<TileMapCell> edited; diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 81dd8bc8a6..2394130ad6 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -922,7 +922,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over // Get the tile modulation. Color modulate = tile_data->get_modulate(); - Color self_modulate = tile_map->get_self_modulate(); + Color self_modulate = tile_map->get_modulate_in_tree() * tile_map->get_self_modulate(); modulate *= self_modulate; modulate *= tile_map->get_layer_modulate(tile_map_layer); @@ -1716,8 +1716,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { // Draw the selection rect. if (tile_set_dragging_selection) { - Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos); - Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos, true); + Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs(); region.size += Vector2i(1, 1); @@ -1812,8 +1812,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven tile_set_selection.clear(); } // Compute the covered area. - Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos); - Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos, true); + Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); if (start_tile != TileSetSource::INVALID_ATLAS_COORDS && end_tile != TileSetSource::INVALID_ATLAS_COORDS) { Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs(); region.size += Vector2i(1, 1); @@ -2236,7 +2236,6 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { scene_tiles_list = memnew(ItemList); scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); - scene_tiles_list->set_drag_forwarding_compat(this); scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI); scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected)); scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked)); @@ -3089,8 +3088,8 @@ void TileMapEditorTerrainsPlugin::_update_terrains_cache() { per_terrain_terrains_patterns.resize(tile_set->get_terrain_sets_count()); for (int i = 0; i < tile_set->get_terrain_sets_count(); i++) { per_terrain_terrains_patterns[i].resize(tile_set->get_terrains_count(i)); - for (int j = 0; j < (int)per_terrain_terrains_patterns[i].size(); j++) { - per_terrain_terrains_patterns[i][j].clear(); + for (RBSet<TileSet::TerrainsPattern> &pattern : per_terrain_terrains_patterns[i]) { + pattern.clear(); } } @@ -3520,8 +3519,8 @@ void TileMapEditor::_update_bottom_panel() { // Update the visibility of controls. missing_tileset_label->set_visible(!tile_set.is_valid()); - for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) { - tabs_data[tab_index].panel->hide(); + for (TileMapEditorPlugin::TabData &tab_data : tabs_data) { + tab_data.panel->hide(); } if (tile_set.is_valid()) { tabs_data[tabs_bar->get_current_tab()].panel->show(); @@ -3610,15 +3609,15 @@ void TileMapEditor::_tab_changed(int p_tab_id) { tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer); // Update toolbar. - for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) { - tabs_data[tab_index].toolbar->hide(); + for (TileMapEditorPlugin::TabData &tab_data : tabs_data) { + tab_data.toolbar->hide(); } tabs_data[p_tab_id].toolbar->show(); // Update visible panel. TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) { - tabs_data[tab_index].panel->hide(); + for (TileMapEditorPlugin::TabData &tab_data : tabs_data) { + tab_data.panel->hide(); } if (tile_map && tile_map->get_tileset().is_valid()) { tabs_data[tabs_bar->get_current_tab()].panel->show(); @@ -3995,10 +3994,10 @@ TileMapEditor::TileMapEditor() { tile_map_toolbar->add_child(tabs_bar); // Tabs toolbars. - for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) { - tabs_data[tab_index].toolbar->hide(); - if (!tabs_data[tab_index].toolbar->get_parent()) { - tile_map_toolbar->add_child(tabs_data[tab_index].toolbar); + for (TileMapEditorPlugin::TabData &tab_data : tabs_data) { + tab_data.toolbar->hide(); + if (!tab_data.toolbar->get_parent()) { + tile_map_toolbar->add_child(tab_data.toolbar); } } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 43eaafc02c..32421daa92 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -110,7 +110,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D")); p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px")); - p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px")); p_list->push_back(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, "")); } @@ -164,7 +164,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na if (p_name == "atlas_coords") { Vector2i as_vector2i = Vector2i(p_value); bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(as_vector2i, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords); - ERR_FAIL_COND_V(!has_room_for_tile, false); + ERR_FAIL_COND_V_EDMSG(!has_room_for_tile, false, "Cannot move the tile, invalid coordinates or not enough room in the atlas for the tile and its animation frames."); if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) { tiles_set_atlas_source_editor->selection.clear(); @@ -223,7 +223,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na for (TileSelection tile : tiles) { bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_separation(tile.tile), tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile); if (!has_room_for_tile) { - ERR_PRINT("No room for tile"); + ERR_PRINT(vformat("Cannot change the number of columns to %s for tile animation. Not enough room in the atlas to layout %s frame(s).", p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile))); } else { tile_set_atlas_source->set_tile_animation_columns(tile.tile, p_value); } @@ -234,7 +234,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na for (TileSelection tile : tiles) { bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile); if (!has_room_for_tile) { - ERR_PRINT("No room for tile"); + ERR_PRINT(vformat("Cannot change separation between frames of the animation to %s. Not enough room in the atlas to layout %s frame(s).", p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile))); } else { tile_set_atlas_source->set_tile_animation_separation(tile.tile, p_value); } @@ -249,11 +249,16 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na return true; } else if (p_name == "animation_frames_count") { for (TileSelection tile : tiles) { - bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), p_value, tile.tile); + int frame_count = p_value; + if (frame_count == 0) { + frame_count = 1; + } + + bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), frame_count, tile.tile); if (!has_room_for_tile) { - ERR_PRINT("No room for tile"); + ERR_PRINT(vformat("Cannot add frames to the animation, not enough room in the atlas to layout %s frames.", frame_count)); } else { - tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, p_value); + tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, frame_count); } } notify_property_list_changed(); @@ -1015,9 +1020,9 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven // Handle the event. Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); @@ -1066,7 +1071,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven // Move tile. Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size(); Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset); - coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); if (drag_current_tile != coords && tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile), tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) { tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords); selection.clear(); @@ -1334,8 +1338,8 @@ void TileSetAtlasSourceEditor::_end_dragging() { undo_redo->commit_action(); } break; case DRAG_TYPE_CREATE_TILES_USING_RECT: { - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size())); undo_redo->create_action(TTR("Create tiles")); @@ -1351,8 +1355,8 @@ void TileSetAtlasSourceEditor::_end_dragging() { undo_redo->commit_action(); } break; case DRAG_TYPE_REMOVE_TILES_USING_RECT: { - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size())); List<PropertyInfo> list; @@ -1402,8 +1406,8 @@ void TileSetAtlasSourceEditor::_end_dragging() { } break; case DRAG_TYPE_RECT_SELECT: { - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); ERR_FAIL_COND(start_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS); ERR_FAIL_COND(new_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS); @@ -1473,12 +1477,12 @@ void TileSetAtlasSourceEditor::_end_dragging() { // We have a tile. menu_option_coords = selected.tile; menu_option_alternative = 0; - base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + base_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i())); } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) { // We don't have a tile, but can create one. menu_option_coords = hovered_base_tile_coords; menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE; - empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + empty_base_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i())); } } break; case DRAG_TYPE_RESIZE_TOP_LEFT: @@ -1771,8 +1775,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { } } else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) { // Draw tiles to be removed. - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size())); @@ -1801,8 +1805,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Vector2i separation = tile_set_atlas_source->get_separation(); Vector2i tile_size = tile_set_atlas_source->get_texture_region_size(); - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size())); for (int x = area.get_position().x; x < area.get_end().x; x++) { @@ -1819,8 +1823,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { // Draw the hovered tile. if (drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT || drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) { // Draw the rect. - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true); Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size())); Vector2i margins = tile_set_atlas_source->get_margins(); @@ -1974,7 +1978,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In selected = selection.front()->get(); menu_option_coords = selected.tile; menu_option_alternative = selected.alternative; - alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + alternative_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i())); } } diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 4f6522f130..53c2d4de51 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -462,6 +462,35 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_ } #define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property)); + + // Add undo method to adding array element. + if (p_array_prefix == "occlusion_layer_") { + if (p_from_index < 0) { + undo_redo_man->add_undo_method(ed_tile_set, "remove_occlusion_layer", p_to_pos < 0 ? ed_tile_set->get_occlusion_layers_count() : p_to_pos); + } + } else if (p_array_prefix == "physics_layer_") { + if (p_from_index < 0) { + undo_redo_man->add_undo_method(ed_tile_set, "remove_physics_layer", p_to_pos < 0 ? ed_tile_set->get_physics_layers_count() : p_to_pos); + } + } else if (p_array_prefix == "terrain_set_") { + if (p_from_index < 0) { + undo_redo_man->add_undo_method(ed_tile_set, "remove_terrain_set", p_to_pos < 0 ? ed_tile_set->get_terrain_sets_count() : p_to_pos); + } + } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") { + int terrain_set = components[0].trim_prefix("terrain_set_").to_int(); + if (p_from_index < 0) { + undo_redo_man->add_undo_method(ed_tile_set, "remove_terrain", terrain_set, p_to_pos < 0 ? ed_tile_set->get_terrains_count(terrain_set) : p_to_pos); + } + } else if (p_array_prefix == "navigation_layer_") { + if (p_from_index < 0) { + undo_redo_man->add_undo_method(ed_tile_set, "remove_navigation_layer", p_to_pos < 0 ? ed_tile_set->get_navigation_layers_count() : p_to_pos); + } + } else if (p_array_prefix == "custom_data_layer_") { + if (p_from_index < 0) { + undo_redo_man->add_undo_method(ed_tile_set, "remove_custom_data_layer", p_to_pos < 0 ? ed_tile_set->get_custom_data_layers_count() : p_to_pos); + } + } + // Save layers' properties. List<PropertyInfo> properties; ed_tile_set->get_property_list(&properties); @@ -543,7 +572,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_ } #undef ADD_UNDO - // Add do method. + // Add do method to add/remove array element. if (p_array_prefix == "occlusion_layer_") { if (p_from_index < 0) { undo_redo_man->add_do_method(ed_tile_set, "add_occlusion_layer", p_to_pos); @@ -637,11 +666,6 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p #undef ADD_UNDO } -void TileSetEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::_can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::_drop_data_fw); -} - void TileSetEditor::edit(Ref<TileSet> p_tile_set) { if (p_tile_set == tile_set) { return; @@ -728,7 +752,7 @@ TileSetEditor::TileSetEditor() { sources_list->add_user_signal(MethodInfo("sort_request")); sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1)); sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); - sources_list->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CDU(sources_list, TileSetEditor); split_container_left_side->add_child(sources_list); HBoxContainer *sources_bottom_actions = memnew(HBoxContainer); diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h index 33200a0632..e3dff11277 100644 --- a/editor/plugins/tiles/tile_set_editor.h +++ b/editor/plugins/tiles/tile_set_editor.h @@ -97,7 +97,6 @@ private: protected: void _notification(int p_what); - static void _bind_methods(); public: _FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; } diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 8d48302f1a..6251cd18f7 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -453,8 +453,6 @@ void TileSetScenesCollectionSourceEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id"))); ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileSetScenesCollectionSourceEditor::_scene_thumbnail_done); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_drop_data_fw); } TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() { @@ -509,7 +507,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() { scene_tiles_list = memnew(ItemList); scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL); scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL); - scene_tiles_list->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CDU(scene_tiles_list, TileSetScenesCollectionSourceEditor); scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1)); scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1)); scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated)); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 2c93d46e38..4c5cde926a 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -4902,10 +4902,6 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred); ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &VisualShaderEditor::drop_data_fw); - ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available); } @@ -4919,7 +4915,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->set_h_size_flags(SIZE_EXPAND_FILL); graph->set_show_zoom_label(true); add_child(graph); - graph->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor); float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature"); @@ -5150,7 +5146,7 @@ VisualShaderEditor::VisualShaderEditor() { members = memnew(Tree); members_vb->add_child(members); - members->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor); members->set_h_size_flags(SIZE_EXPAND_FILL); members->set_v_size_flags(SIZE_EXPAND_FILL); members->set_hide_root(true); @@ -5190,7 +5186,7 @@ VisualShaderEditor::VisualShaderEditor() { members_dialog->set_ok_button_text(TTR("Create")); members_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create)); members_dialog->get_ok_button()->set_disabled(true); - members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel)); + members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel)); add_child(members_dialog); // add varyings dialog @@ -5445,11 +5441,9 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Binormal", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Color", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("DepthTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture", "DEPTH_TEXTURE"), { "depth_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FragCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FrontFacing", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing", "FRONT_FACING"), { "front_facing" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("ScreenTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); @@ -5492,7 +5486,6 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("NormalTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture", "NORMAL_TEXTURE"), { "normal_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ScreenPixelSize", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size", "SCREEN_PIXEL_SIZE"), { "screen_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ScreenTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("SpecularShininess", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("SpecularShininessTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE"), { "specular_shininess_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); @@ -5696,7 +5689,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR)); curve_xyz_node_option_idx = add_options.size(); add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D)); - add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value of the DEPTH_TEXTURE node in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value obtained from the depth prepass in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); texture2d_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D)); texture2d_array_node_option_idx = add_options.size(); diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index a3ccf392e6..f9f72fee77 100644 --- a/editor/plugins/voxel_gi_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -35,7 +35,9 @@ void VoxelGIEditorPlugin::_bake() { if (voxel_gi) { - if (voxel_gi->get_probe_data().is_null()) { + Ref<VoxelGIData> voxel_gi_data = voxel_gi->get_probe_data(); + + if (voxel_gi_data.is_null()) { String path = get_tree()->get_edited_scene_root()->get_scene_file_path(); if (path.is_empty()) { path = "res://" + voxel_gi->get_name() + "_data.res"; @@ -46,7 +48,32 @@ void VoxelGIEditorPlugin::_bake() { probe_file->set_current_path(path); probe_file->popup_file_dialog(); return; + } else { + String path = voxel_gi_data->get_path(); + if (!path.is_resource_file()) { + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is not local to the scene.")); + return; + } + } else { + if (FileAccess::exists(base + ".import")) { + EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is part of an imported resource.")); + return; + } + } + } + } else { + if (FileAccess::exists(path + ".import")) { + EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is an imported resource.")); + return; + } + } } + voxel_gi->bake(); } } diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index db11f80826..37f941c7b2 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -195,7 +195,7 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p cancel_hb->hide(); } cancel_hb->move_to_front(); - cancelled = false; + canceled = false; _popup(); if (p_can_cancel) { cancel->grab_focus(); @@ -203,12 +203,12 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p } bool ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) { - ERR_FAIL_COND_V(!tasks.has(p_task), cancelled); + ERR_FAIL_COND_V(!tasks.has(p_task), canceled); if (!p_force_redraw) { uint64_t tus = OS::get_singleton()->get_ticks_usec(); if (tus - last_progress_tick < 200000) { //200ms - return cancelled; + return canceled; } } @@ -228,7 +228,7 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int #ifndef ANDROID_ENABLED Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor #endif - return cancelled; + return canceled; } void ProgressDialog::end_task(const String &p_task) { @@ -246,7 +246,7 @@ void ProgressDialog::end_task(const String &p_task) { } void ProgressDialog::_cancel_pressed() { - cancelled = true; + canceled = true; } void ProgressDialog::_bind_methods() { diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h index 5346f01a9e..7ac4864c9c 100644 --- a/editor/progress_dialog.h +++ b/editor/progress_dialog.h @@ -85,7 +85,7 @@ class ProgressDialog : public PopupPanel { void _popup(); void _cancel_pressed(); - bool cancelled = false; + bool canceled = false; protected: void _notification(int p_what); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 8396d50a0e..727b2c9b4d 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -210,6 +210,7 @@ static const char *gdscript_function_renames[][2] = { // { "set_v_offset", "set_drag_vertical_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // {"get_points","get_points_id"},// Astar, broke Line2D, Convexpolygonshape // {"get_v_scroll","get_v_scroll_bar"},//ItemList, broke TextView + // { "get_stylebox", "get_theme_stylebox" }, // Control - Will rename the method in Theme as well, skipping { "_about_to_show", "_about_to_popup" }, // ColorPickerButton { "_get_configuration_warning", "_get_configuration_warnings" }, // Node { "_set_current", "set_current" }, // Camera2D @@ -237,7 +238,6 @@ static const char *gdscript_function_renames[][2] = { { "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image { "can_be_hidden", "_can_be_hidden" }, // EditorNode3DGizmoPlugin { "can_drop_data", "_can_drop_data" }, // Control - { "can_drop_data_fw", "_can_drop_data_fw" }, // ScriptEditor { "can_generate_small_preview", "_can_generate_small_preview" }, // EditorResourcePreviewGenerator { "can_instance", "can_instantiate" }, // PackedScene, Script { "canvas_light_set_scale", "canvas_light_set_texture_scale" }, // RenderingServer @@ -264,7 +264,6 @@ static const char *gdscript_function_renames[][2] = { { "deselect_items", "deselect_all" }, // FileDialog { "disable_plugin", "_disable_plugin" }, // EditorPlugin { "drop_data", "_drop_data" }, // Control - { "drop_data_fw", "_drop_data_fw" }, // ScriptEditor { "exclude_polygons_2d", "exclude_polygons" }, // Geometry2D { "find_node", "find_child" }, // Node { "find_scancode_from_string", "find_keycode_from_string" }, // OS @@ -303,7 +302,6 @@ static const char *gdscript_function_renames[][2] = { { "get_d", "get_distance" }, // LineShape2D { "get_depth_bias_enable", "get_depth_bias_enabled" }, // RDPipelineRasterizationState { "get_drag_data", "_get_drag_data" }, // Control - { "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor { "get_editor_viewport", "get_editor_main_screen" }, // EditorPlugin { "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton { "get_endian_swap", "is_big_endian" }, // File @@ -668,6 +666,7 @@ static const char *csharp_function_renames[][2] = { // { "SetVOffset", "SetDragVerticalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // {"GetPoints","GetPointsId"},// Astar, broke Line2D, Convexpolygonshape // {"GetVScroll","GetVScrollBar"},//ItemList, broke TextView + // { "GetStylebox", "GetThemeStylebox" }, // Control - Will rename the method in Theme as well, skipping { "AddSpatialGizmoPlugin", "AddNode3dGizmoPlugin" }, // EditorPlugin { "RenderingServer", "GetTabAlignment" }, // Tab { "_AboutToShow", "_AboutToPopup" }, // ColorPickerButton @@ -1081,6 +1080,7 @@ static const char *gdscript_properties_renames[][2] = { // { "zfar", "far" }, // Camera3D // { "znear", "near" }, // Camera3D // { "filename", "scene_file_path" }, // Node + // { "pressed", "button_pressed" }, // BaseButton - Will also rename the signal, skipping for now { "as_normalmap", "as_normal_map" }, // NoiseTexture { "bbcode_text", "text" }, // RichTextLabel { "bg", "panel" }, // Theme @@ -1116,6 +1116,7 @@ static const char *gdscript_properties_renames[][2] = { { "gravity_vec", "gravity_direction" }, // Area2D { "hint_tooltip", "tooltip_text" }, // Control { "hseparation", "h_separation" }, // Theme + { "icon_align", "icon_alignment" }, // Button { "iterations_per_second", "physics_ticks_per_second" }, // Engine { "invert_enable", "invert_enabled" }, // Polygon2D { "margin_bottom", "offset_bottom" }, // Control broke NinePatchRect, StyleBox @@ -1140,7 +1141,7 @@ static const char *gdscript_properties_renames[][2] = { { "rect_position", "position" }, // Control { "rect_global_position", "global_position" }, // Control { "rect_size", "size" }, // Control - { "rect_min_size", "minimum_size" }, // Control + { "rect_min_size", "custom_minimum_size" }, // Control { "rect_rotation", "rotation" }, // Control { "rect_scale", "scale" }, // Control { "rect_pivot_offset", "pivot_offset" }, // Control @@ -1195,6 +1196,7 @@ static const char *csharp_properties_renames[][2] = { // { "WrapEnabled", "WrapMode" }, // TextEdit // { "Zfar", "Far" }, // Camera3D // { "Znear", "Near" }, // Camera3D + // { "Pressed", "ButtonPressed" }, // BaseButton - Will also rename the signal, skipping for now { "AsNormalmap", "AsNormalMap" }, // NoiseTexture { "BbcodeText", "Text" }, // RichTextLabel { "CaretBlinkSpeed", "CaretBlinkInterval" }, // TextEdit, LineEdit @@ -1224,6 +1226,7 @@ static const char *csharp_properties_renames[][2] = { { "GravityVec", "GravityDirection" }, // Area2D { "HintTooltip", "TooltipText" }, // Control { "Hseparation", "HSeparation" }, // Theme + { "IconAlign", "IconAlignment" }, // Button { "IterationsPerSecond", "PhysicsTicksPerSecond" }, // Engine { "InvertEnable", "InvertEnabled" }, // Polygon2D { "MarginBottom", "OffsetBottom" }, // Control broke NinePatchRect, StyleBox @@ -1282,6 +1285,7 @@ static const char *gdscript_signals_renames[][2] = { // {"changed","settings_changed"}, // EditorSettings { "about_to_show", "about_to_popup" }, // Popup { "button_release", "button_released" }, // XRController3D + { "cancelled", "canceled" }, // AcceptDialog { "network_peer_connected", "peer_connected" }, // MultiplayerAPI { "network_peer_disconnected", "peer_disconnected" }, // MultiplayerAPI { "network_peer_packet", "peer_packet" }, // MultiplayerAPI @@ -1366,6 +1370,18 @@ static const char *project_settings_renames[][2] = { { nullptr, nullptr }, }; +static const char *input_map_renames[][2] = { + { ",\"alt\":", ",\"alt_pressed\":" }, + { ",\"shift\":", ",\"shift_pressed\":" }, + { ",\"control\":", ",\"ctrl_pressed\":" }, + { ",\"meta\":", ",\"meta_pressed\":" }, + { ",\"scancode\":", ",\"keycode\":" }, + { ",\"physical_scancode\":", ",\"physical_keycode\":" }, + { ",\"doubleclick\":", ",\"double_click\":" }, + + { nullptr, nullptr }, +}; + static const char *builtin_types_renames[][2] = { { "PoolByteArray", "PackedByteArray" }, { "PoolColorArray", "PackedColorArray" }, @@ -1774,6 +1790,19 @@ static const char *color_renames[][2] = { { nullptr, nullptr }, }; +// Find "OS.set_property(x)", capturing x into $1. +static String make_regex_gds_os_property_set(String name_set) { + return String("\\bOS\\.") + name_set + "\\s*\\((.*)\\)"; +} +// Find "OS.property = x", capturing x into $1 or $2. +static String make_regex_gds_os_property_assign(String name) { + return String("\\bOS\\.") + name + "\\s*=\\s*([^#]+)"; +} +// Find "OS.property" OR "OS.get_property()" / "OS.is_property()". +static String make_regex_gds_os_property_get(String name, String get) { + return String("\\bOS\\.(") + get + "_)?" + name + "(\\s*\\(\\s*\\))?"; +} + class ProjectConverter3To4::RegExContainer { public: // Custom GDScript. @@ -1791,8 +1820,37 @@ public: RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)"); RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)"); RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)"); - RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)"); RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)"); + // Simple OS properties with getters/setters. + RegEx reg_os_current_screen = RegEx("\\bOS\\.(set_|get_)?current_screen\\b"); + RegEx reg_os_min_window_size = RegEx("\\bOS\\.(set_|get_)?min_window_size\\b"); + RegEx reg_os_max_window_size = RegEx("\\bOS\\.(set_|get_)?max_window_size\\b"); + RegEx reg_os_window_position = RegEx("\\bOS\\.(set_|get_)?window_position\\b"); + RegEx reg_os_window_size = RegEx("\\bOS\\.(set_|get_)?window_size\\b"); + RegEx reg_os_getset_screen_orient = RegEx("\\bOS\\.(s|g)et_screen_orientation\\b"); + // OS property getters/setters for non trivial replacements. + RegEx reg_os_set_window_resizable = RegEx(make_regex_gds_os_property_set("set_window_resizable")); + RegEx reg_os_assign_window_resizable = RegEx(make_regex_gds_os_property_assign("window_resizable")); + RegEx reg_os_is_window_resizable = RegEx(make_regex_gds_os_property_get("window_resizable", "is")); + RegEx reg_os_set_fullscreen = RegEx(make_regex_gds_os_property_set("set_window_fullscreen")); + RegEx reg_os_assign_fullscreen = RegEx(make_regex_gds_os_property_assign("window_fullscreen")); + RegEx reg_os_is_fullscreen = RegEx(make_regex_gds_os_property_get("window_fullscreen", "is")); + RegEx reg_os_set_maximized = RegEx(make_regex_gds_os_property_set("set_window_maximized")); + RegEx reg_os_assign_maximized = RegEx(make_regex_gds_os_property_assign("window_maximized")); + RegEx reg_os_is_maximized = RegEx(make_regex_gds_os_property_get("window_maximized", "is")); + RegEx reg_os_set_minimized = RegEx(make_regex_gds_os_property_set("set_window_minimized")); + RegEx reg_os_assign_minimized = RegEx(make_regex_gds_os_property_assign("window_minimized")); + RegEx reg_os_is_minimized = RegEx(make_regex_gds_os_property_get("window_minimized", "is")); + RegEx reg_os_set_vsync = RegEx(make_regex_gds_os_property_set("set_use_vsync")); + RegEx reg_os_assign_vsync = RegEx(make_regex_gds_os_property_assign("vsync_enabled")); + RegEx reg_os_is_vsync = RegEx(make_regex_gds_os_property_get("vsync_enabled", "is")); + // OS properties specific cases & specific replacements. + RegEx reg_os_assign_screen_orient = RegEx("^(\\s*)OS\\.screen_orientation\\s*=\\s*([^#]+)"); // $1 - indent, $2 - value + RegEx reg_os_set_always_on_top = RegEx(make_regex_gds_os_property_set("set_window_always_on_top")); + RegEx reg_os_is_always_on_top = RegEx("\\bOS\\.is_window_always_on_top\\s*\\(.*\\)"); + RegEx reg_os_set_borderless = RegEx(make_regex_gds_os_property_set("set_borderless_window")); + RegEx reg_os_get_borderless = RegEx("\\bOS\\.get_borderless_window\\s*\\(\\s*\\)"); + RegEx reg_os_screen_orient_enum = RegEx("\\bOS\\.SCREEN_ORIENTATION_(\\w+)\\b"); // $1 - constant suffix // GDScript keywords. RegEx keyword_gdscript_tool = RegEx("^tool"); @@ -1839,6 +1897,7 @@ public: LocalVector<RegEx *> enum_regexes; LocalVector<RegEx *> gdscript_function_regexes; LocalVector<RegEx *> project_settings_regexes; + LocalVector<RegEx *> input_map_regexes; LocalVector<RegEx *> gdscript_properties_regexes; LocalVector<RegEx *> gdscript_signals_regexes; LocalVector<RegEx *> shaders_regexes; @@ -1862,6 +1921,10 @@ public: for (unsigned int current_index = 0; project_settings_renames[current_index][0]; current_index++) { project_settings_regexes.push_back(memnew(RegEx(String("\\b") + project_settings_renames[current_index][0] + "\\b"))); } + // Input Map. + for (unsigned int current_index = 0; input_map_renames[current_index][0]; current_index++) { + input_map_regexes.push_back(memnew(RegEx(String("\\b") + input_map_renames[current_index][0] + "\\b"))); + } // GDScript properties. for (unsigned int current_index = 0; gdscript_properties_renames[current_index][0]; current_index++) { gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_properties_renames[current_index][0] + "\\b"))); @@ -1915,8 +1978,8 @@ public: } } ~RegExContainer() { - for (unsigned int i = 0; i < color_regexes.size(); i++) { - memdelete(color_regexes[i]); + for (RegEx *regex : color_regexes) { + memdelete(regex); } for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) { memdelete(class_tscn_regexes[i]); @@ -1924,35 +1987,38 @@ public: memdelete(class_shader_regexes[i]); memdelete(class_regexes[i]); } - for (unsigned int i = 0; i < enum_regexes.size(); i++) { - memdelete(enum_regexes[i]); + for (RegEx *regex : enum_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < gdscript_function_regexes.size(); i++) { - memdelete(gdscript_function_regexes[i]); + for (RegEx *regex : gdscript_function_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < project_settings_regexes.size(); i++) { - memdelete(project_settings_regexes[i]); + for (RegEx *regex : project_settings_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < gdscript_properties_regexes.size(); i++) { - memdelete(gdscript_properties_regexes[i]); + for (RegEx *regex : input_map_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < gdscript_signals_regexes.size(); i++) { - memdelete(gdscript_signals_regexes[i]); + for (RegEx *regex : gdscript_properties_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < shaders_regexes.size(); i++) { - memdelete(shaders_regexes[i]); + for (RegEx *regex : gdscript_signals_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < builtin_types_regexes.size(); i++) { - memdelete(builtin_types_regexes[i]); + for (RegEx *regex : shaders_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < csharp_function_regexes.size(); i++) { - memdelete(csharp_function_regexes[i]); + for (RegEx *regex : builtin_types_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < csharp_properties_regexes.size(); i++) { - memdelete(csharp_properties_regexes[i]); + for (RegEx *regex : csharp_function_regexes) { + memdelete(regex); } - for (unsigned int i = 0; i < csharp_signal_regexes.size(); i++) { - memdelete(csharp_signal_regexes[i]); + for (RegEx *regex : csharp_properties_regexes) { + memdelete(regex); + } + for (RegEx *regex : csharp_signal_regexes) { + memdelete(regex); } } }; @@ -2084,6 +2150,7 @@ int ProjectConverter3To4::convert() { } else if (file_name.ends_with("project.godot")) { rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); + rename_common(input_map_renames, reg_container.input_map_regexes, lines); } else if (file_name.ends_with(".csproj")) { // TODO } else { @@ -2249,6 +2316,7 @@ int ProjectConverter3To4::validate_conversion() { } else if (file_name.ends_with("project.godot")) { changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); + changed_elements.append_array(check_for_rename_common(input_map_renames, reg_container.input_map_regexes, lines)); } else if (file_name.ends_with(".csproj")) { // TODO } else { @@ -2385,6 +2453,8 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { valid = valid && test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, reg_container.project_settings_regexes, "project setting"); + valid = valid && test_conversion_basic("\"device\":-1,\"alt\":false,\"shift\":false,\"control\":false,\"meta\":false,\"doubleclick\":false,\"scancode\":0,\"physical_scancode\":16777254,\"script\":null", "\"device\":-1,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"double_click\":false,\"keycode\":0,\"physical_keycode\":16777254,\"script\":null", input_map_renames, reg_container.input_map_regexes, "input map"); + valid = valid && test_conversion_basic("Transform", "Transform3D", builtin_types_renames, reg_container.builtin_types_regexes, "builtin type"); // Custom Renames. @@ -2402,8 +2472,41 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); - valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "if Settings.fullscreen:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid && test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.window_resizable: pass", "\tif (not get_window().unresizable): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_resizable(): pass", "\tif (not get_window().unresizable): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_resizable(Settings.resizable)", "\tget_window().unresizable = not (Settings.resizable)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.window_resizable = Settings.resizable", "\tget_window().unresizable = not (Settings.resizable)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.window_fullscreen: pass", "\tif ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_fullscreen(): pass", "\tif ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_fullscreen(Settings.fullscreen)", "\tget_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.window_fullscreen = Settings.fullscreen", "\tget_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.window_maximized: pass", "\tif (get_window().mode == Window.MODE_MAXIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_maximized(): pass", "\tif (get_window().mode == Window.MODE_MAXIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_maximized(Settings.maximized)", "\tget_window().mode = Window.MODE_MAXIMIZED if (Settings.maximized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.window_maximized = Settings.maximized", "\tget_window().mode = Window.MODE_MAXIMIZED if (Settings.maximized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.window_minimized: pass", "\tif (get_window().mode == Window.MODE_MINIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_minimized(): pass", "\tif (get_window().mode == Window.MODE_MINIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_minimized(Settings.minimized)", "\tget_window().mode = Window.MODE_MINIMIZED if (Settings.minimized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.window_minimized = Settings.minimized", "\tget_window().mode = Window.MODE_MINIMIZED if (Settings.minimized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.vsync_enabled: pass", "\tif (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.is_vsync_enabled(): pass", "\tif (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_use_vsync(Settings.vsync)", "\tDisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (Settings.vsync) else DisplayServer.VSYNC_DISABLED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.vsync_enabled = Settings.vsync", "\tDisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (Settings.vsync) else DisplayServer.VSYNC_DISABLED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.screen_orientation = OS.SCREEN_ORIENTATION_VERTICAL: pass", "\tif DisplayServer.screen_get_orientation() = DisplayServer.SCREEN_VERTICAL: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tif OS.get_screen_orientation() = OS.SCREEN_ORIENTATION_LANDSCAPE: pass", "\tif DisplayServer.screen_get_orientation() = DisplayServer.SCREEN_LANDSCAPE: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_screen_orientation(Settings.orient)", "\tDisplayServer.screen_set_orientation(Settings.orient)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.screen_orientation = Settings.orient", "\tDisplayServer.screen_set_orientation(Settings.orient)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_always_on_top(): pass", "\tif get_window().always_on_top: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_always_on_top(Settings.alwaystop)", "\tget_window().always_on_top = (Settings.alwaystop)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid && test_conversion_gdscript_builtin("\tif OS.get_borderless_window(): pass", "\tif get_window().borderless: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("\tOS.set_borderless_window(Settings.borderless)", "\tget_window().borderless = (Settings.borderless)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); @@ -2740,6 +2843,7 @@ bool ProjectConverter3To4::test_array_names() { valid = valid && test_single_array(shaders_renames, true); valid = valid && test_single_array(gdscript_signals_renames); valid = valid && test_single_array(project_settings_renames); + valid = valid && test_single_array(input_map_renames); valid = valid && test_single_array(builtin_types_renames); valid = valid && test_single_array(color_renames); @@ -3166,9 +3270,96 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai line = reg_container.reg_setget_get.sub(line, "var $1$2: get = $3", true); } - // OS.window_fullscreen = a -> if a: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) + if (line.contains("window_resizable")) { + // OS.set_window_resizable(a) -> get_window().unresizable = not (a) + line = reg_container.reg_os_set_window_resizable.sub(line, "get_window().unresizable = not ($1)", true); + // OS.window_resizable = a -> same + line = reg_container.reg_os_assign_window_resizable.sub(line, "get_window().unresizable = not ($1)", true); + // OS.[is_]window_resizable() -> (not get_window().unresizable) + line = reg_container.reg_os_is_window_resizable.sub(line, "(not get_window().unresizable)", true); + } + if (line.contains("window_fullscreen")) { - line = reg_container.reg_os_fullscreen.sub(line, "if $1:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", true); + // OS.window_fullscreen(a) -> get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (a) else Window.MODE_WINDOWED + line = reg_container.reg_os_set_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true); + // window_fullscreen = a -> same + line = reg_container.reg_os_assign_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true); + // OS.[is_]window_fullscreen() -> ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)) + line = reg_container.reg_os_is_fullscreen.sub(line, "((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))", true); + } + + if (line.contains("window_maximized")) { + // OS.window_maximized(a) -> get_window().mode = Window.MODE_MAXIMIZED if (a) else Window.MODE_WINDOWED + line = reg_container.reg_os_set_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true); + // window_maximized = a -> same + line = reg_container.reg_os_assign_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true); + // OS.[is_]window_maximized() -> (get_window().mode == Window.MODE_MAXIMIZED) + line = reg_container.reg_os_is_maximized.sub(line, "(get_window().mode == Window.MODE_MAXIMIZED)", true); + } + + if (line.contains("window_minimized")) { + // OS.window_minimized(a) -> get_window().mode = Window.MODE_MINIMIZED if (a) else Window.MODE_WINDOWED + line = reg_container.reg_os_set_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true); + // window_minimized = a -> same + line = reg_container.reg_os_assign_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true); + // OS.[is_]window_minimized() -> (get_window().mode == Window.MODE_MINIMIZED) + line = reg_container.reg_os_is_minimized.sub(line, "(get_window().mode == Window.MODE_MINIMIZED)", true); + } + + if (line.contains("set_use_vsync")) { + // OS.set_use_vsync(a) -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED) + line = reg_container.reg_os_set_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true); + } + if (line.contains("vsync_enabled")) { + // vsync_enabled = a -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED) + line = reg_container.reg_os_assign_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true); + // OS.[is_]vsync_enabled() -> (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED) + line = reg_container.reg_os_is_vsync.sub(line, "(DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)", true); + } + + if (line.contains("OS.screen_orientation")) { // keep "OS." at start + // OS.screen_orientation = a -> DisplayServer.screen_set_orientation(a) + line = reg_container.reg_os_assign_screen_orient.sub(line, "$1DisplayServer.screen_set_orientation($2)", true); // assignment + line = line.replace("OS.screen_orientation", "DisplayServer.screen_get_orientation()"); // value access + } + + if (line.contains("_window_always_on_top")) { + // OS.set_window_always_on_top(a) -> get_window().always_on_top = (a) + line = reg_container.reg_os_set_always_on_top.sub(line, "get_window().always_on_top = ($1)", true); + // OS.is_window_always_on_top() -> get_window().always_on_top + line = reg_container.reg_os_is_always_on_top.sub(line, "get_window().always_on_top", true); + } + + if (line.contains("et_borderless_window")) { + // OS.set_borderless_window(a) -> get_window().borderless = (a) + line = reg_container.reg_os_set_borderless.sub(line, "get_window().borderless = ($1)", true); + // OS.get_borderless_window() -> get_window().borderless + line = reg_container.reg_os_get_borderless.sub(line, "get_window().borderless", true); + } + + // OS.SCREEN_ORIENTATION_* -> DisplayServer.SCREEN_* + if (line.contains("OS.SCREEN_ORIENTATION_")) { + line = reg_container.reg_os_screen_orient_enum.sub(line, "DisplayServer.SCREEN_$1", true); + } + + // OS -> Window simple replacements with optional set/get. + if (line.contains("current_screen")) { + line = reg_container.reg_os_current_screen.sub(line, "get_window().$1current_screen", true); + } + if (line.contains("min_window_size")) { + line = reg_container.reg_os_min_window_size.sub(line, "get_window().$1min_size", true); + } + if (line.contains("max_window_size")) { + line = reg_container.reg_os_max_window_size.sub(line, "get_window().$1max_size", true); + } + if (line.contains("window_position")) { + line = reg_container.reg_os_window_position.sub(line, "get_window().$1position", true); + } + if (line.contains("window_size")) { + line = reg_container.reg_os_window_size.sub(line, "get_window().$1size", true); + } + if (line.contains("et_screen_orientation")) { + line = reg_container.reg_os_getset_screen_orient.sub(line, "DisplayServer.screen_$1et_orientation", true); } // Instantiate @@ -3669,11 +3860,85 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai if (line.contains("OS.get_datetime")) { line = line.replace("OS.get_datetime", "Time.get_datetime_dict_from_system"); } + + // OS -> DisplayServer + if (line.contains("OS.get_display_cutouts")) { + line = line.replace("OS.get_display_cutouts", "DisplayServer.get_display_cutouts"); + } + if (line.contains("OS.get_screen_count")) { + line = line.replace("OS.get_screen_count", "DisplayServer.get_screen_count"); + } + if (line.contains("OS.get_screen_dpi")) { + line = line.replace("OS.get_screen_dpi", "DisplayServer.screen_get_dpi"); + } + if (line.contains("OS.get_screen_max_scale")) { + line = line.replace("OS.get_screen_max_scale", "DisplayServer.screen_get_max_scale"); + } + if (line.contains("OS.get_screen_position")) { + line = line.replace("OS.get_screen_position", "DisplayServer.screen_get_position"); + } + if (line.contains("OS.get_screen_refresh_rate")) { + line = line.replace("OS.get_screen_refresh_rate", "DisplayServer.screen_get_refresh_rate"); + } + if (line.contains("OS.get_screen_scale")) { + line = line.replace("OS.get_screen_scale", "DisplayServer.screen_get_scale"); + } + if (line.contains("OS.get_screen_size")) { + line = line.replace("OS.get_screen_size", "DisplayServer.screen_get_size"); + } + if (line.contains("OS.set_icon")) { + line = line.replace("OS.set_icon", "DisplayServer.set_icon"); + } + if (line.contains("OS.set_native_icon")) { + line = line.replace("OS.set_native_icon", "DisplayServer.set_native_icon"); + } + + // OS -> Window + if (line.contains("OS.window_borderless")) { + line = line.replace("OS.window_borderless", "get_window().borderless"); + } + if (line.contains("OS.get_real_window_size")) { + line = line.replace("OS.get_real_window_size", "get_window().get_size_with_decorations"); + } + if (line.contains("OS.is_window_focused")) { + line = line.replace("OS.is_window_focused", "get_window().has_focus"); + } + if (line.contains("OS.move_window_to_foreground")) { + line = line.replace("OS.move_window_to_foreground", "get_window().move_to_foreground"); + } + if (line.contains("OS.request_attention")) { + line = line.replace("OS.request_attention", "get_window().request_attention"); + } + if (line.contains("OS.set_window_title")) { + line = line.replace("OS.set_window_title", "get_window().set_title"); + } + + // get_tree().set_input_as_handled() -> get_viewport().set_input_as_handled() + if (line.contains("get_tree().set_input_as_handled()")) { + line = line.replace("get_tree().set_input_as_handled()", "get_viewport().set_input_as_handled()"); + } + + // Fix the simple case of using _unhandled_key_input + // func _unhandled_key_input(event: InputEventKey) -> _unhandled_key_input(event: InputEvent) + if (line.contains("_unhandled_key_input(event: InputEventKey)")) { + line = line.replace("_unhandled_key_input(event: InputEventKey)", "_unhandled_key_input(event: InputEvent)"); + } } void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer ®_container) { line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()"); + // GetTree().SetInputAsHandled() -> GetViewport().SetInputAsHandled() + if (line.contains("GetTree().SetInputAsHandled()")) { + line = line.replace("GetTree().SetInputAsHandled()", "GetViewport().SetInputAsHandled()"); + } + + // Fix the simple case of using _UnhandledKeyInput + // func _UnhandledKeyInput(InputEventKey @event) -> _UnhandledKeyInput(InputEvent @event) + if (line.contains("_UnhandledKeyInput(InputEventKey @event)")) { + line = line.replace("_UnhandledKeyInput(InputEventKey @event)", "_UnhandledKeyInput(InputEvent @event)"); + } + // -- Connect(,,,things) -> Connect(,Callable(,),things) Object if (line.contains("Connect(")) { int start = line.find("Connect("); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index 5f6b5aa42f..061baaff7e 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -219,6 +219,4 @@ void unregister_editor_types() { if (EditorPaths::get_singleton()) { EditorPaths::free(); } - - EditorResourcePicker::clear_caches(); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 733f140a56..5d1a2a49c5 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1428,6 +1428,9 @@ void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) { void SceneTreeDock::_push_item(Object *p_object) { EditorNode::get_singleton()->push_item(p_object); + if (p_object == nullptr) { + EditorNode::get_singleton()->hide_unused_editors(this); + } } void SceneTreeDock::_handle_select(Node *p_node) { @@ -2004,13 +2007,13 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { void SceneTreeDock::_script_creation_closed() { script_create_dialog->disconnect("script_created", callable_mp(this, &SceneTreeDock::_script_created)); script_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_script_creation_closed)); - script_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_script_creation_closed)); + script_create_dialog->disconnect("canceled", callable_mp(this, &SceneTreeDock::_script_creation_closed)); } void SceneTreeDock::_shader_creation_closed() { shader_create_dialog->disconnect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); shader_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); - shader_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->disconnect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); } void SceneTreeDock::_toggle_editable_children_from_selection() { @@ -2061,7 +2064,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { return; } - EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false); + EditorNode::get_singleton()->hide_unused_editors(this); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(p_cut ? TTR("Cut Node(s)") : TTR("Remove Node(s)"), UndoRedo::MERGE_DISABLE, remove_list.front()->get()); @@ -3090,7 +3093,7 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) { script_create_dialog->connect("script_created", callable_mp(this, &SceneTreeDock::_script_created)); script_create_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_script_creation_closed)); - script_create_dialog->connect("cancelled", callable_mp(this, &SceneTreeDock::_script_creation_closed)); + script_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_script_creation_closed)); script_create_dialog->set_inheritance_base_type("Node"); script_create_dialog->config(inherits, path); script_create_dialog->popup_centered(); @@ -3132,7 +3135,7 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) { shader_create_dialog->connect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); shader_create_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); - shader_create_dialog->connect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); shader_create_dialog->config(path, true, true, -1, p_preferred_mode); shader_create_dialog->popup_centered(); } diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 148dcd862a..e795cc919c 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -677,7 +677,7 @@ bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArra for (int i = 0; i < p_terms.size(); i++) { String term = p_terms[i]; - // Recognise special filter. + // Recognize special filter. if (term.contains(":") && !term.get_slicec(':', 0).is_empty()) { String parameter = term.get_slicec(':', 0); String argument = term.get_slicec(':', 1); @@ -1373,10 +1373,6 @@ void SceneTreeEditor::_bind_methods() { ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node); ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SceneTreeEditor::drop_data_fw); - ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree); ADD_SIGNAL(MethodInfo("node_selected")); @@ -1419,7 +1415,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope add_child(tree); - tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCD(tree, SceneTreeEditor); if (p_can_rename) { tree->set_allow_rmb_select(true); tree->connect("item_mouse_selected", callable_mp(this, &SceneTreeEditor::_rmb_select)); diff --git a/editor/translations/af.po b/editor/translations/af.po index a705eb58fb..605b30cf67 100644 --- a/editor/translations/af.po +++ b/editor/translations/af.po @@ -11201,7 +11201,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/ar.po b/editor/translations/ar.po index 204dd9a41b..327332ae18 100644 --- a/editor/translations/ar.po +++ b/editor/translations/ar.po @@ -70,13 +70,14 @@ # xX-Void-Xx <arandomdude75@gmail.com>, 2022. # Ø£Øمد النور <ahmed2699@gmail.com>, 2022. # Commander Gordon <gordoncommander@gmail.com>, 2022. +# Abdulrahman <abdelrahman.ramadan686@gmail.com>, 2022. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-10-29 23:55+0000\n" -"Last-Translator: Commander Gordon <gordoncommander@gmail.com>\n" +"PO-Revision-Date: 2022-12-21 07:01+0000\n" +"Last-Translator: Abdulrahman <abdelrahman.ramadan686@gmail.com>\n" "Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/" "godot/ar/>\n" "Language: ar\n" @@ -85,7 +86,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" -"X-Generator: Weblate 4.14.2-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -877,7 +878,7 @@ msgstr "مطابقة المساÙات الطويلة" #: core/project_settings.cpp msgid "Compression Level" -msgstr "ضغط المستوى" +msgstr "مستوى الضغط" #: core/project_settings.cpp msgid "Window Log Size" @@ -11177,7 +11178,7 @@ msgstr "نظر من الخلÙ" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [البوابات Ù…Ùعلة]" @@ -28516,6 +28517,5 @@ msgid "Log Active Async Compiles Count" msgstr "" #: servers/visual_server.cpp -#, fuzzy msgid "Shader Cache Size (MB)" -msgstr "غيّر Øجم الكاميرا" +msgstr "Øجم ذاكرة التظليل المؤقتة (مب)" diff --git a/editor/translations/az.po b/editor/translations/az.po index b6b36d99e5..90dfffe257 100644 --- a/editor/translations/az.po +++ b/editor/translations/az.po @@ -10789,7 +10789,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/bg.po b/editor/translations/bg.po index 262a6825a6..728ffabe29 100644 --- a/editor/translations/bg.po +++ b/editor/translations/bg.po @@ -10946,7 +10946,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/bn.po b/editor/translations/bn.po index df79cd5d84..b601d6d668 100644 --- a/editor/translations/bn.po +++ b/editor/translations/bn.po @@ -13,13 +13,14 @@ # Hasibul Hasan <d1hasib@yahoo.com>, 2020. # saitama <atik.wowspace@gmail.com>, 2022. # Joysankar Majumdar <joymajumdar15828@gmail.com>, 2022. +# Safuan <safuanhossain12616@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-06-29 10:04+0000\n" -"Last-Translator: Joysankar Majumdar <joymajumdar15828@gmail.com>\n" +"PO-Revision-Date: 2023-01-09 20:42+0000\n" +"Last-Translator: Safuan <safuanhossain12616@gmail.com>\n" "Language-Team: Bengali <https://hosted.weblate.org/projects/godot-engine/" "godot/bn/>\n" "Language: bn\n" @@ -27,7 +28,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Weblate 4.13.1-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -50,14 +51,12 @@ msgid "V-Sync Enabled" msgstr "à¦à¦¿-সিঙà§à¦• সকà§à¦°à¦¿à¦¯à¦¼ করà§à¦¨" #: core/bind/core_bind.cpp main/main.cpp -#, fuzzy msgid "V-Sync Via Compositor" msgstr "কমà§à¦ªà¦¸à¦¿à¦Ÿà¦° দà§à¦¬à¦¾à¦°à¦¾ à¦à¦¿-সিঙà§à¦• করা" #: core/bind/core_bind.cpp main/main.cpp -#, fuzzy msgid "Delta Smoothing" -msgstr "ডেলà§à¦Ÿà¦¾ মসৃণ করন" +msgstr "ডেলà§à¦Ÿà¦¾ মসৃণ" #: core/bind/core_bind.cpp #, fuzzy @@ -86,7 +85,6 @@ msgstr "পরà§à¦¦à¦¾ à¦à§‹à¦à¦•/ উপসà§à¦¥à¦¾à¦ªà¦¨" #: core/bind/core_bind.cpp core/project_settings.cpp main/main.cpp #: platform/uwp/os_uwp.cpp -#, fuzzy msgid "Window" msgstr "উইনà§à¦¡à§‹" @@ -156,9 +154,8 @@ msgid "Target FPS" msgstr "লকà§à¦·à§à¦¯-à¦à¦«à¦ªà¦¿à¦à¦¸(ফà§à¦°à§‡à¦®-পà§à¦°à¦¤à¦¿-সেকেনà§à¦¡)" #: core/bind/core_bind.cpp -#, fuzzy msgid "Time Scale" -msgstr "টাইম-সà§à¦•à§‡à¦² নোড" +msgstr "টাইম-সà§à¦•à§‡à¦²" #: core/bind/core_bind.cpp main/main.cpp #, fuzzy @@ -11772,7 +11769,7 @@ msgstr "পরিপà§à¦°à§‡à¦•à§à¦·à¦¿à¦¤ (Perspective)" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/br.po b/editor/translations/br.po index 0cfc29b4d1..41d6ac8ee8 100644 --- a/editor/translations/br.po +++ b/editor/translations/br.po @@ -10666,7 +10666,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/ca.po b/editor/translations/ca.po index d3ced0a876..ab408a0d9f 100644 --- a/editor/translations/ca.po +++ b/editor/translations/ca.po @@ -11292,7 +11292,7 @@ msgstr "Perspectiva" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/cs.po b/editor/translations/cs.po index 173d38c85c..ee5bb962be 100644 --- a/editor/translations/cs.po +++ b/editor/translations/cs.po @@ -32,13 +32,13 @@ # JoeMoos <josephmoose13@gmail.com>, 2022. # Mirinek <mirek.nozicka77@gmail.com>, 2022. # LubomÃr Baloun <lubosbaloun@gmail.com>, 2022. -# OndÅ™ej Pavelka <flamekick97@gmail.com>, 2022. +# OndÅ™ej Pavelka <flamekick97@gmail.com>, 2022, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-12-12 09:46+0000\n" +"PO-Revision-Date: 2023-01-06 09:58+0000\n" "Last-Translator: OndÅ™ej Pavelka <flamekick97@gmail.com>\n" "Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/" "cs/>\n" @@ -47,7 +47,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -251,9 +251,8 @@ msgstr "Data" #: modules/gdscript/language_server/gdscript_language_server.cpp #: modules/webrtc/webrtc_data_channel.h modules/websocket/websocket_macros.h #: scene/gui/file_dialog.cpp -#, fuzzy msgid "Network" -msgstr "SÃÅ¥ový profiler" +msgstr "SÃÅ¥" #: core/io/file_access_network.cpp #, fuzzy @@ -605,9 +604,8 @@ msgid "Application" msgstr "Akce" #: core/project_settings.cpp main/main.cpp -#, fuzzy msgid "Config" -msgstr "Nastavenà pÅ™ichycenÃ" +msgstr "Konfigurace" #: core/project_settings.cpp #, fuzzy @@ -1582,9 +1580,8 @@ msgid "Editors" msgstr "Editory" #: editor/animation_track_editor.cpp editor/editor_settings.cpp -#, fuzzy msgid "Confirm Insert Track" -msgstr "Animace: Vložit stopu a klÃÄ" +msgstr "Potvrdit vloženà stopy" #. TRANSLATORS: %s will be replaced by a phrase describing the target of track. #: editor/animation_track_editor.cpp @@ -4547,17 +4544,16 @@ msgid "Version Control" msgstr "Správa verzÃ" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Username" -msgstr "PÅ™ejmenovat" +msgstr "Uživatelské jméno" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "SSH Public Key Path" -msgstr "" +msgstr "Cesta k veÅ™ejnému klÃÄi SSH" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "SSH Private Key Path" -msgstr "" +msgstr "Cesta k soukromému klÃÄi SSH" #: editor/editor_node.cpp msgid "Dock Position" @@ -5191,12 +5187,11 @@ msgstr "Ladicà program" #: editor/editor_profiler.cpp msgid "Profiler Frame History Size" -msgstr "" +msgstr "Velikost historie profilovacÃho rámce" #: editor/editor_profiler.cpp -#, fuzzy msgid "Profiler Frame Max Functions" -msgstr "PÅ™ejmenovat funkci" +msgstr "Maximálnà poÄet funkcà profilovacÃho rámce" #: editor/editor_properties.cpp msgid "Edit Text:" @@ -5723,82 +5718,78 @@ msgid "Show Members Overview" msgstr "Zobrazit pÅ™ehled Älenů" #: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Files" -msgstr "Soubor" +msgstr "Soubory" #: editor/editor_settings.cpp -#, fuzzy msgid "Trim Trailing Whitespace On Save" -msgstr "Osekat koncové mezery" +msgstr "Osekat koncové mezery pÅ™i uloženÃ" #: editor/editor_settings.cpp msgid "Autosave Interval Secs" -msgstr "" +msgstr "Interval automatického ukládánà v sekundách" #: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp msgid "Restore Scripts On Load" -msgstr "" +msgstr "Obnovit skripty pÅ™i naÄtenÃ" #: editor/editor_settings.cpp msgid "Auto Reload And Parse Scripts On Save" -msgstr "" +msgstr "Automaticky aktualizovat a parsovat skripty pÅ™i uloženÃ" #: editor/editor_settings.cpp msgid "Auto Reload Scripts On External Change" -msgstr "" +msgstr "Automaticky aktualizovat skripty pÅ™i externà zmÄ›nÄ›" #: editor/editor_settings.cpp msgid "Create Signal Callbacks" -msgstr "" +msgstr "VytvoÅ™it callback signálu" #: editor/editor_settings.cpp msgid "Sort Members Outline Alphabetically" -msgstr "" +msgstr "SeÅ™adit pÅ™ehled Älenů abecednÄ›" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Cursor" -msgstr "" +msgstr "Kurzor" #: editor/editor_settings.cpp msgid "Scroll Past End Of File" -msgstr "" +msgstr "Skrolovat za konec souboru" #: editor/editor_settings.cpp msgid "Block Caret" -msgstr "" +msgstr "Blokovat stÅ™ÃÅ¡ku" #: editor/editor_settings.cpp msgid "Caret Blink" -msgstr "" +msgstr "Blikánà stÅ™ÃÅ¡ky" #: editor/editor_settings.cpp msgid "Caret Blink Speed" -msgstr "" +msgstr "Rychlost blikánà stÅ™ÃÅ¡ky" #: editor/editor_settings.cpp -#, fuzzy msgid "Right Click Moves Caret" -msgstr "Pravý klik pro pÅ™idánà bodu" +msgstr "Pravý klik posune stÅ™ÃÅ¡ku" #: editor/editor_settings.cpp modules/gdscript/gdscript.cpp #: modules/gdscript/gdscript_editor.cpp #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion" -msgstr "KopÃrovat výbÄ›r" +msgstr "DokonÄovánÃ" #: editor/editor_settings.cpp msgid "Idle Parse Delay" -msgstr "" +msgstr "ZpoždÄ›nà parsovánà pÅ™i neÄinnosti" #: editor/editor_settings.cpp msgid "Auto Brace Complete" -msgstr "" +msgstr "Automatické doplnÄ›nà závorky" #: editor/editor_settings.cpp msgid "Code Complete Delay" -msgstr "" +msgstr "ZpoždÄ›nà dokonÄenà kódu" #: editor/editor_settings.cpp msgid "Put Callhint Tooltip Below Current Line" @@ -5806,87 +5797,76 @@ msgstr "" #: editor/editor_settings.cpp msgid "Callhint Tooltip Offset" -msgstr "" +msgstr "Posunutà nápovÄ›dy" #: editor/editor_settings.cpp -#, fuzzy msgid "Complete File Paths" -msgstr "KopÃrovat cestu k uzlu" +msgstr "DokonÄit cestu k souboru" #: editor/editor_settings.cpp modules/gdscript/gdscript_editor.cpp -#, fuzzy msgid "Add Type Hints" -msgstr "PÅ™idat typ" +msgstr "PÅ™idat nápovÄ›dy typů" #: editor/editor_settings.cpp -#, fuzzy msgid "Use Single Quotes" -msgstr "Nová dlaždice" +msgstr "PoužÃvat jednoduché závorky" #: editor/editor_settings.cpp -#, fuzzy msgid "Show Help Index" -msgstr "Zobrazit pomocnÃky" +msgstr "Zobrazit index nápovÄ›dy" #: editor/editor_settings.cpp msgid "Help Font Size" -msgstr "" +msgstr "Velikost fontu nápovÄ›dy" #: editor/editor_settings.cpp msgid "Help Source Font Size" -msgstr "" +msgstr "Velikost fontu zdroje nápovÄ›dy" #: editor/editor_settings.cpp msgid "Help Title Font Size" -msgstr "" +msgstr "Velikost fontu titulku nápovÄ›dy" #: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp msgid "Grid Map" msgstr "MřÞková mapa" #: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp -#, fuzzy msgid "Pick Distance" -msgstr "Vybrat vzdálenost:" +msgstr "VýbÄ›rová vzdálenost" #: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Preview Size" -msgstr "Náhled" +msgstr "Velikost náhledu" #: editor/editor_settings.cpp msgid "Primary Grid Color" -msgstr "" +msgstr "Primárnà barva mřÞky" #: editor/editor_settings.cpp msgid "Secondary Grid Color" -msgstr "" +msgstr "Sekundárnà barva mřÞky" #: editor/editor_settings.cpp -#, fuzzy msgid "Selection Box Color" -msgstr "Pouze výbÄ›r" +msgstr "Barva výbÄ›rového pole" #: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp -#, fuzzy msgid "3D Gizmos" -msgstr "Gizma" +msgstr "3D Rukojeti" #: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp -#, fuzzy msgid "Gizmo Colors" -msgstr "Emisnà barvy" +msgstr "Barvy rukojetÃ" #: editor/editor_settings.cpp -#, fuzzy msgid "Instanced" -msgstr "Instance" +msgstr "Instancováno" #: editor/editor_settings.cpp modules/gltf/gltf_node.cpp #: scene/3d/physics_body.cpp -#, fuzzy msgid "Joint" msgstr "Bod" @@ -5897,12 +5877,11 @@ msgstr "Bod" #: scene/resources/particles_material.cpp servers/physics_2d_server.cpp #: servers/physics_server.cpp msgid "Shape" -msgstr "" +msgstr "Tvar" #: editor/editor_settings.cpp -#, fuzzy msgid "Primary Grid Steps" -msgstr "Krok mřÞky:" +msgstr "Primárnà stupnÄ› mřÞky" #: editor/editor_settings.cpp msgid "Grid Size" @@ -5910,35 +5889,31 @@ msgstr "Velikost mřÞky" #: editor/editor_settings.cpp msgid "Grid Division Level Max" -msgstr "" +msgstr "Maximálnà úroveň rozdÄ›lenà mřÞky" #: editor/editor_settings.cpp msgid "Grid Division Level Min" -msgstr "" +msgstr "Minimálnà úroveň rozdÄ›lenà mřÞky" #: editor/editor_settings.cpp msgid "Grid Division Level Bias" -msgstr "" +msgstr "Sklon úrovnÄ› rozdÄ›lenà mřÞky" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid XZ Plane" -msgstr "Vykreslit GridMap" +msgstr "Rovina XZ mřÞky" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid XY Plane" -msgstr "Vykreslit GridMap" +msgstr "Rovina XY mřÞky" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid YZ Plane" -msgstr "Vykreslit GridMap" +msgstr "Rovina YZ mřÞky" #: editor/editor_settings.cpp -#, fuzzy msgid "Default FOV" -msgstr "VýchozÃ" +msgstr "Výchozà FOV" #: editor/editor_settings.cpp #, fuzzy @@ -5946,222 +5921,194 @@ msgid "Default Z Near" msgstr "Výchozà motiv" #: editor/editor_settings.cpp -#, fuzzy msgid "Default Z Far" -msgstr "VýchozÃ" +msgstr "Výchozà Z limit dálky" #: editor/editor_settings.cpp msgid "Lightmap Baking Number Of CPU Threads" -msgstr "" +msgstr "PoÄet CPU vláken pÅ™i zapékánà svÄ›telných map" #: editor/editor_settings.cpp -#, fuzzy msgid "Navigation Scheme" -msgstr "NavigaÄnà režim" +msgstr "Schéma navigace" #: editor/editor_settings.cpp -#, fuzzy msgid "Invert Y Axis" -msgstr "Editovat osu Y" +msgstr "Invertovat osu Y" #: editor/editor_settings.cpp -#, fuzzy msgid "Invert X Axis" -msgstr "Editovat osu X" +msgstr "Invertovat osu X" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Style" -msgstr "ZmenÅ¡it" +msgstr "Styl pÅ™iblÞenÃ" #: editor/editor_settings.cpp msgid "Emulate Numpad" -msgstr "" +msgstr "Emulovat numerickou klávesnici" #: editor/editor_settings.cpp msgid "Emulate 3 Button Mouse" -msgstr "" +msgstr "Emulovat tÅ™ÃtlaÄÃtkovou myÅ¡" #: editor/editor_settings.cpp -#, fuzzy msgid "Orbit Modifier" -msgstr "SeÅ™adit podle prvnà zmÄ›ny" +msgstr "Modifikátor orbitu" #: editor/editor_settings.cpp -#, fuzzy msgid "Pan Modifier" -msgstr "Režim posouvánÃ" +msgstr "Modifikátor posouvánÃ" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Modifier" -msgstr "Úpravy" +msgstr "Modifikátor pÅ™iblÞenÃ" #: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Warped Mouse Panning" -msgstr "" +msgstr "Zkreslené posouvánà myÅ¡i" #: editor/editor_settings.cpp -#, fuzzy msgid "Navigation Feel" -msgstr "NavigaÄnà režim" +msgstr "Pocit navigace" #: editor/editor_settings.cpp msgid "Orbit Sensitivity" -msgstr "" +msgstr "Citlivost orbitu" #: editor/editor_settings.cpp msgid "Orbit Inertia" -msgstr "" +msgstr "SetrvaÄnost orbitu" #: editor/editor_settings.cpp -#, fuzzy msgid "Translation Inertia" -msgstr "PÅ™eklady" +msgstr "SetrvaÄnost pÅ™ekladu" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Inertia" -msgstr "ZvÄ›tÅ¡it" +msgstr "SetrvaÄnost pÅ™iblÞenÃ" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook" -msgstr "Volný pohled nahoru" +msgstr "Volný pohled" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Navigation Scheme" -msgstr "VytvoÅ™it Navigation Mesh" +msgstr "NavigaÄnà schéma volného pohledu" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Sensitivity" -msgstr "Volný pohled doleva" +msgstr "Senzitivita volného pohledu" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Inertia" -msgstr "Volný pohled doleva" +msgstr "SetrvaÄnost volného pohledu" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Base Speed" -msgstr "Rychlost volného pohledu" +msgstr "Základnà rychlost volného pohledu" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Activation Modifier" -msgstr "Zpomalenà volného pohledu" +msgstr "Modifikátor aktivace volného pohledu" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Speed Zoom Link" -msgstr "Rychlost volného pohledu" +msgstr "Link rychlo pÅ™iblÞenà volného pohledu" #: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Grid Color" -msgstr "Vyberte barvu" +msgstr "Barva mřÞky" #: editor/editor_settings.cpp -#, fuzzy msgid "Guides Color" -msgstr "Vyberte barvu" +msgstr "Barva vodÃtek" #: editor/editor_settings.cpp -#, fuzzy msgid "Smart Snapping Line Color" -msgstr "Chytré pÅ™ichcovánÃ" +msgstr "Barva linky chytrého pÅ™ichycovánÃ" #: editor/editor_settings.cpp msgid "Bone Width" -msgstr "" +msgstr "Å ÃÅ™ka kosti" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Color 1" -msgstr "Odstranit položky tÅ™Ãdy" +msgstr "Barva kosti 1" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Color 2" -msgstr "Odstranit položky tÅ™Ãdy" +msgstr "Barva kosti 2" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Selected Color" -msgstr "Konfigurace vybraného profilu:" +msgstr "Barva vybrané kosti" #: editor/editor_settings.cpp msgid "Bone IK Color" -msgstr "" +msgstr "Barva IK kosti" #: editor/editor_settings.cpp msgid "Bone Outline Color" -msgstr "" +msgstr "Barva obrysu kosti" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Outline Size" -msgstr "Velikost obrysu:" +msgstr "Velikost obrysu kosti" #: editor/editor_settings.cpp +#, fuzzy msgid "Viewport Border Color" -msgstr "" +msgstr "Barva ohraniÄenà výřezu" #: editor/editor_settings.cpp +#, fuzzy msgid "Constrain Editor View" -msgstr "" +msgstr "Omezit pohled editoru" #: editor/editor_settings.cpp msgid "Simple Panning" -msgstr "" +msgstr "Jednoduché posouvánÃ" #: editor/editor_settings.cpp msgid "Scroll To Pan" -msgstr "" +msgstr "Skrollovat pro posun" #: editor/editor_settings.cpp -#, fuzzy msgid "Pan Speed" -msgstr "Rychlost:" +msgstr "Rychlost posunu" #: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Poly Editor" -msgstr "Polygon 2D UV Editor" +msgstr "Editor polygonů" #: editor/editor_settings.cpp msgid "Point Grab Radius" -msgstr "" +msgstr "Dosah pro uchopenà bodu" #: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Show Previous Outline" -msgstr "PÅ™edchozà rovina" +msgstr "Zobrazit pÅ™edchozà obrys" #: editor/editor_settings.cpp editor/scene_tree_dock.cpp -#, fuzzy msgid "Autorename Animation Tracks" -msgstr "PÅ™ejmenovat animaci" +msgstr "Automaticky pÅ™ejmenovat animaÄnà stopy" #: editor/editor_settings.cpp msgid "Default Create Bezier Tracks" -msgstr "" +msgstr "Výchozà vytvářenà beziérových stop" #: editor/editor_settings.cpp -#, fuzzy msgid "Default Create Reset Tracks" -msgstr "VytvoÅ™it RESET stopu/stopy" +msgstr "Výchozà vytvářenà resetovacÃch stop" #: editor/editor_settings.cpp msgid "Onion Layers Past Color" -msgstr "" +msgstr "Barva cibulových vrstev minulosti" #: editor/editor_settings.cpp msgid "Onion Layers Future Color" -msgstr "" +msgstr "Barva cibulových vrstev budoucnosti" #: editor/editor_settings.cpp msgid "Visual Editors" @@ -6169,11 +6116,11 @@ msgstr "Vizuálnà editory" #: editor/editor_settings.cpp msgid "Minimap Opacity" -msgstr "" +msgstr "Průhlednost minimapy" #: editor/editor_settings.cpp msgid "Window Placement" -msgstr "" +msgstr "UmÃstÄ›nà okna" #: editor/editor_settings.cpp scene/2d/back_buffer_copy.cpp scene/2d/sprite.cpp #: scene/2d/visibility_notifier_2d.cpp scene/3d/sprite_3d.cpp @@ -6183,49 +6130,42 @@ msgid "Rect" msgstr "Celý obdélnÃk" #: editor/editor_settings.cpp -#, fuzzy msgid "Rect Custom Position" -msgstr "Nastavit bod z kÅ™ivky" +msgstr "Vlastnà pozice okna" #: editor/editor_settings.cpp platform/android/export/export_plugin.cpp msgid "Screen" msgstr "" #: editor/editor_settings.cpp -#, fuzzy msgid "Auto Save" -msgstr "Automatický Å™ez" +msgstr "Automatické ukládánÃ" #: editor/editor_settings.cpp -#, fuzzy msgid "Save Before Running" -msgstr "Uložit scénu pÅ™ed spuÅ¡tÄ›nÃm..." +msgstr "Uložit pÅ™ed spuÅ¡tÄ›nÃm" #: editor/editor_settings.cpp -#, fuzzy msgid "Font Size" -msgstr "Pohled zepÅ™edu" +msgstr "Velikost fontu" #: editor/editor_settings.cpp #: modules/gdscript/language_server/gdscript_language_server.cpp -#, fuzzy msgid "Remote Host" -msgstr "Vzdálený " +msgstr "Vzdálený host" #: editor/editor_settings.cpp #: modules/gdscript/language_server/gdscript_language_server.cpp -#, fuzzy msgid "Remote Port" -msgstr "Odstranit bod" +msgstr "Vzdálený port" #: editor/editor_settings.cpp -#, fuzzy msgid "Editor SSL Certificates" -msgstr "Nastavenà editoru" +msgstr "SSL certifikáty editoru" #: editor/editor_settings.cpp msgid "HTTP Proxy" -msgstr "" +msgstr "HTTP Proxy" #: editor/editor_settings.cpp msgid "Host" @@ -6244,9 +6184,8 @@ msgstr "Správce projektů" #. TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects. #: editor/editor_settings.cpp -#, fuzzy msgid "Sorting Order" -msgstr "PÅ™ejmenovánà složky:" +msgstr "SeÅ™adit podle" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Symbol Color" @@ -6322,11 +6261,11 @@ msgstr "ÄŒÃslo řádku:" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Caret Color" -msgstr "Barva vynechávky" +msgstr "Barva stÅ™ÃÅ¡ky" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Caret Background Color" -msgstr "Barva pozadà vynechávky" +msgstr "Barva pozadà stÅ™ÃÅ¡ky" #: editor/editor_settings.cpp msgid "Text Selected Color" @@ -7309,9 +7248,8 @@ msgid "Use Named Skins" msgstr "PoužÃt Å¡kálovacàpÅ™ichytávánÃ" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "External Files" -msgstr "OtevÅ™Ãt soubor" +msgstr "Externà soubory" #: editor/import/resource_importer_scene.cpp msgid "Store In Subdir" @@ -8293,7 +8231,7 @@ msgstr "Vynutit bÃlou modulaci" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Include Gizmos (3D)" -msgstr "Zahrnout Gizmos (3D)" +msgstr "Zahrnout rukojeti (3D)" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Pin AnimationPlayer" @@ -8681,9 +8619,8 @@ msgid "Download Error" msgstr "Chyba pÅ™i stahovánÃ" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Available URLs" -msgstr "Dostupné profily:" +msgstr "Dostupné URL" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Download for this asset is already in progress!" @@ -8771,7 +8708,7 @@ msgstr "Kategorie:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Site:" -msgstr "Web:" +msgstr "Stránka:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Support" @@ -9346,7 +9283,7 @@ msgstr "VytvoÅ™it kosti z uzlů" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Clear Custom Bones" -msgstr "Vymazat kosti" +msgstr "Vymazat vlastnà kosti" #. TRANSLATORS: Noun, name of the 2D/3D View menus. #: editor/plugins/canvas_item_editor_plugin.cpp @@ -9715,7 +9652,7 @@ msgstr "Pravý klik pro pÅ™idánà bodu" #: editor/plugins/gi_probe_editor_plugin.cpp msgid "Bake GI Probe" -msgstr "Zapéct GI probe" +msgstr "Zapéct GI sondu" #: editor/plugins/gradient_editor_plugin.cpp msgid "Gradient Edited" @@ -10338,7 +10275,7 @@ msgstr "RozdÄ›lit segment (v kÅ™ivce)" #: editor/plugins/physical_bone_plugin.cpp msgid "Move Joint" -msgstr "PÅ™esunout kloub" +msgstr "Posunout bod" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "" @@ -10885,14 +10822,12 @@ msgid "External" msgstr "ExternÃ" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Use External Editor" -msgstr "Debugovat v externÃm editoru" +msgstr "PoužÃvat externà editor" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Exec Path" -msgstr "Exportovat cestu" +msgstr "Cesta k spuÅ¡tÄ›nÃ" #: editor/plugins/script_editor_plugin.cpp msgid "Script Temperature Enabled" @@ -10920,11 +10855,11 @@ msgstr "SeÅ™adit skripty podle" #: editor/plugins/script_editor_plugin.cpp msgid "List Script Names As" -msgstr "Zobrazit názvy seznamu skriptů jako" +msgstr "Zobrazit seznam názvů skriptů jako" #: editor/plugins/script_editor_plugin.cpp msgid "Exec Flags" -msgstr "" +msgstr "Parametry spuÅ¡tÄ›nÃ" #: editor/plugins/script_editor_plugin.cpp msgid "Clear Recent Scripts" @@ -11254,7 +11189,7 @@ msgstr "PerspektivnÃ" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [aktivnà portály]" @@ -11462,35 +11397,35 @@ msgstr "Nenà k dispozici pÅ™i použità vykreslovacÃho modulu GLES2." #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Left" -msgstr "Volný pohled doleva" +msgstr "Levý volný pohled" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Right" -msgstr "Volný pohled doprava" +msgstr "Pravý volný pohled" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Forward" -msgstr "Volný pohled vpÅ™ed" +msgstr "PÅ™ednà volný pohled" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Backwards" -msgstr "Volný pohled dozadu" +msgstr "Zadnà volný pohled" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Up" -msgstr "Volný pohled nahoru" +msgstr "Hornà volný pohled" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Down" -msgstr "Volný pohled dolů" +msgstr "Dolnà volný pohled" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Speed Modifier" -msgstr "Rychlost volného pohledu" +msgstr "Modifikátor rychlosti volného pohybu" #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Slow Modifier" -msgstr "Zpomalenà volného pohledu" +msgstr "Modifikátor zpomalenà volného pohybu" #: editor/plugins/spatial_editor_plugin.cpp msgid "Toggle Camera Preview" @@ -11756,16 +11691,15 @@ msgstr "Po" #: editor/plugins/spatial_editor_plugin.cpp msgid "Manipulator Gizmo Size" -msgstr "" +msgstr "Nastavenà velikosti rukojeti" #: editor/plugins/spatial_editor_plugin.cpp msgid "Manipulator Gizmo Opacity" -msgstr "" +msgstr "Nastavenà průhlednosti rukojeti" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Show Viewport Rotation Gizmo" -msgstr "Uzamknout rotaci pohledu" +msgstr "Zobrazit tlaÄÃtko rotace zobrazenÃ" #: editor/plugins/spatial_editor_plugin.cpp msgid "Unnamed Gizmo" @@ -12748,55 +12682,46 @@ msgid "Clear Transform" msgstr "Promazat transformaci" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Tile Map" -msgstr "Nakreslit TileMap" +msgstr "Mapa dlaždic" #: editor/plugins/tile_map_editor_plugin.cpp #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Palette Min Width" -msgstr "" +msgstr "Minimálnà šÃÅ™ka palety" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Palette Item H Separation" -msgstr "Nazvaný oddÄ›lovaÄ" +msgstr "H oddÄ›lovánà paletových položek" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Show Tile Names" -msgstr "Zobrazit vÅ¡echny jazyky" +msgstr "Zobrazit názvy dlaždic" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Show Tile Ids" -msgstr "Zobrazit pravÃtka" +msgstr "Zobrazit Id dlaždic" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Sort Tiles By Name" -msgstr "SeÅ™adit soubory" +msgstr "Řadit dlaždice podle názvu" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Bucket Fill Preview" -msgstr "Vyplnit barvou" +msgstr "Náhled vyplnÄ›nà kbelÃkem" #: editor/plugins/tile_map_editor_plugin.cpp #: modules/gridmap/grid_map_editor_plugin.cpp -#, fuzzy msgid "Editor Side" -msgstr "Editor" +msgstr "Strana editoru" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Display Grid" -msgstr "Rentgen pohled" +msgstr "Zobrazit mřÞku" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Axis Color" -msgstr "Vyberte barvu" +msgstr "Barva osy" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Add Texture(s) to TileSet." @@ -13331,7 +13256,7 @@ msgstr "Resetovat" #: editor/plugins/version_control_editor_plugin.cpp msgid "Version Control System" -msgstr "Verzovánà (VCS)" +msgstr "Systémy pro správu verzÃ" #: editor/plugins/version_control_editor_plugin.cpp msgid "Initialize" @@ -13344,11 +13269,11 @@ msgstr "Odstranit bod" #: editor/plugins/version_control_editor_plugin.cpp msgid "Select SSH public key path" -msgstr "" +msgstr "Vybrat cestu k veÅ™ejnému klÃÄi SSH" #: editor/plugins/version_control_editor_plugin.cpp msgid "Select SSH private key path" -msgstr "" +msgstr "Vybrat cestu k veÅ™ejnému klÃÄi SSH" #: editor/plugins/version_control_editor_plugin.cpp msgid "SSH Passphrase" @@ -16148,15 +16073,15 @@ msgstr "Filtrovat dlaždice" #: editor/script_editor_debugger.cpp msgid "Auto Switch To Remote Scene Tree" -msgstr "" +msgstr "Automaticky pÅ™epnout na vzdálený strom scén" #: editor/script_editor_debugger.cpp msgid "Remote Scene Tree Refresh Interval" -msgstr "" +msgstr "Interval obnovenà vzdáleného stromu scén" #: editor/script_editor_debugger.cpp msgid "Remote Inspect Refresh Interval" -msgstr "" +msgstr "Interval obnovenà vzdálené kontroly" #: editor/script_editor_debugger.cpp msgid "Network Profiler" @@ -16254,7 +16179,7 @@ msgstr "ZmÄ›nit rádius svÄ›tla" #: editor/spatial_editor_gizmos.cpp msgid "Stream Player 3D" -msgstr "" +msgstr "Stream Player 3D" #: editor/spatial_editor_gizmos.cpp msgid "Change AudioStreamPlayer3D Emission Angle" @@ -16264,7 +16189,7 @@ msgstr "ZmÄ›nit úhel vysÃlánà uzlu AudioStreamPlayer3D" #: platform/osx/export/export.cpp #: scene/resources/default_theme/default_theme.cpp msgid "Camera" -msgstr "" +msgstr "Kamera" #: editor/spatial_editor_gizmos.cpp msgid "Change Camera FOV" @@ -16276,7 +16201,7 @@ msgstr "ZmÄ›nit velikost kamery" #: editor/spatial_editor_gizmos.cpp msgid "Visibility Notifier" -msgstr "" +msgstr "Oznamovatel viditelnosti" #: editor/spatial_editor_gizmos.cpp msgid "Change Notifier AABB" @@ -16287,23 +16212,20 @@ msgid "Change Particles AABB" msgstr "ZmÄ›nit Äástice AABB" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "Reflection Probe" -msgstr "Vybrat vlastnost" +msgstr "Reflexnà sonda" #: editor/spatial_editor_gizmos.cpp msgid "Change Probe Extents" msgstr "ZmÄ›nit rozsahy Probe" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "GI Probe" -msgstr "Zapéct GI probe" +msgstr "GI Sonda" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "Baked Indirect Light" -msgstr "NepÅ™Ãmé osvÄ›tlenÃ" +msgstr "ZapeÄené nepÅ™Ãmé osvÄ›tlenÃ" #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp msgid "Change Sphere Shape Radius" @@ -16334,40 +16256,36 @@ msgid "Change Ray Shape Length" msgstr "ZmÄ›nit délku Ray Shape" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "Navigation Edge" -msgstr "NavigaÄnà režim" +msgstr "Hrana navigace" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "Navigation Edge Disabled" -msgstr "NavigaÄnà režim" +msgstr "Hrana navigace vypnuta" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "Navigation Solid" -msgstr "NavigaÄnà režim" +msgstr "Pevná navigace" #: editor/spatial_editor_gizmos.cpp -#, fuzzy msgid "Navigation Solid Disabled" -msgstr "NavigaÄnà režim" +msgstr "Pevná navigace vypnuta" #: editor/spatial_editor_gizmos.cpp msgid "Joint Body A" -msgstr "" +msgstr "Kloubové tÄ›lo A" #: editor/spatial_editor_gizmos.cpp msgid "Joint Body B" -msgstr "" +msgstr "Kloubové tÄ›lo B" #: editor/spatial_editor_gizmos.cpp msgid "Room Edge" -msgstr "" +msgstr "Hrana mÃstnosti" #: editor/spatial_editor_gizmos.cpp msgid "Room Overlap" -msgstr "" +msgstr "PÅ™ekrytà mÃstnostÃ" #: editor/spatial_editor_gizmos.cpp #, fuzzy @@ -16375,17 +16293,16 @@ msgid "Set Room Point Position" msgstr "Nastavit pozici bodu kÅ™ivky" #: editor/spatial_editor_gizmos.cpp scene/3d/portal.cpp -#, fuzzy msgid "Portal Margin" -msgstr "Nastavit okraj" +msgstr "Okraj portálu" #: editor/spatial_editor_gizmos.cpp msgid "Portal Edge" -msgstr "" +msgstr "Hrana portálu" #: editor/spatial_editor_gizmos.cpp msgid "Portal Arrow" -msgstr "" +msgstr "Å ipka portálu" #: editor/spatial_editor_gizmos.cpp #, fuzzy @@ -16403,9 +16320,8 @@ msgstr "JÃt zpÄ›t" #: editor/spatial_editor_gizmos.cpp scene/2d/light_occluder_2d.cpp #: scene/2d/tile_map.cpp -#, fuzzy msgid "Occluder" -msgstr "Režim okluze" +msgstr "Okluzor" #: editor/spatial_editor_gizmos.cpp #, fuzzy @@ -16849,7 +16765,7 @@ msgstr "" #: modules/csg/csg_gizmos.cpp msgid "CSG" -msgstr "" +msgstr "CSG" #: modules/csg/csg_gizmos.cpp msgid "Change Cylinder Radius" @@ -17215,18 +17131,16 @@ msgid "Object can't provide a length." msgstr "Objekt nemůže poskytnout délku." #: modules/gdscript/language_server/gdscript_language_server.cpp -#, fuzzy msgid "Language Server" -msgstr "Jazyk:" +msgstr "Jazykový server" #: modules/gdscript/language_server/gdscript_language_server.cpp -#, fuzzy msgid "Enable Smart Resolve" -msgstr "Nelze vyÅ™eÅ¡it" +msgstr "Povolit funkci chytrého Å™eÅ¡enÃ" #: modules/gdscript/language_server/gdscript_language_server.cpp msgid "Show Native Symbols In Editor" -msgstr "" +msgstr "Zobrazenà nativnÃch symbolů v editoru" #: modules/gdscript/language_server/gdscript_language_server.cpp msgid "Use Thread" @@ -17398,9 +17312,8 @@ msgid "Children" msgstr "Upravitelnà potomci" #: modules/gltf/gltf_skeleton.cpp modules/gltf/gltf_skin.cpp -#, fuzzy msgid "Joints" -msgstr "Bod" +msgstr "Body" #: modules/gltf/gltf_skeleton.cpp modules/gltf/gltf_skin.cpp msgid "Roots" @@ -17521,7 +17434,7 @@ msgstr "" #: modules/gltf/gltf_state.cpp msgid "Cameras" -msgstr "" +msgstr "Kamery" #: modules/gltf/gltf_state.cpp servers/visual_server.cpp #, fuzzy @@ -17729,7 +17642,7 @@ msgstr "Nastavenà GridMap" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Pick Distance:" -msgstr "Vybrat vzdálenost:" +msgstr "VýbÄ›rová vzdálenost:" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Filter meshes" @@ -18793,7 +18706,7 @@ msgstr "Prioritnà mód" #: modules/webrtc/webrtc_data_channel.h msgid "WebRTC" -msgstr "" +msgstr "WebRTC" #: modules/webrtc/webrtc_data_channel.h msgid "Max Channel In Buffer (KB)" @@ -18801,11 +18714,11 @@ msgstr "" #: modules/websocket/websocket_client.cpp msgid "Verify SSL" -msgstr "" +msgstr "Ověřit SSL" #: modules/websocket/websocket_client.cpp msgid "Trusted SSL Certificate" -msgstr "" +msgstr "DůvÄ›ryhodný certifikát SSL" #: modules/websocket/websocket_macros.h #, fuzzy @@ -18844,7 +18757,7 @@ msgstr "Fyzická Klávesa" #: modules/websocket/websocket_server.cpp platform/javascript/export/export.cpp msgid "SSL Certificate" -msgstr "" +msgstr "Certifikát SSL" #: modules/websocket/websocket_server.cpp #, fuzzy @@ -18896,28 +18809,27 @@ msgstr "Chytré pÅ™ichcovánÃ" #: platform/android/export/export.cpp msgid "Android SDK Path" -msgstr "" +msgstr "Cesta k Android SDK" #: platform/android/export/export.cpp -#, fuzzy msgid "Debug Keystore" -msgstr "Ladicà program" +msgstr "LadÄ›nà Keystore" #: platform/android/export/export.cpp msgid "Debug Keystore User" -msgstr "" +msgstr "Uživatel ladÄ›nà Keystore" #: platform/android/export/export.cpp msgid "Debug Keystore Pass" -msgstr "" +msgstr "Průchod ladÄ›nà Keystore" #: platform/android/export/export.cpp msgid "Force System User" -msgstr "" +msgstr "Vynutit systémového uživatele" #: platform/android/export/export.cpp msgid "Shutdown ADB On Exit" -msgstr "" +msgstr "Vypnout ADB pÅ™i ukonÄenÃ" #: platform/android/export/export_plugin.cpp msgid "Launcher Icons" @@ -19000,7 +18912,7 @@ msgstr "Ladicà program" #: platform/android/export/export_plugin.cpp platform/uwp/export/export.cpp msgid "Debug Password" -msgstr "" +msgstr "Heslo ladÄ›nÃ" #: platform/android/export/export_plugin.cpp #, fuzzy @@ -19873,7 +19785,7 @@ msgstr "Chyba pÅ™i spuÅ¡tÄ›nà serveru HTTP:" #: platform/javascript/export/export.cpp msgid "Web" -msgstr "" +msgstr "Web" #: platform/javascript/export/export.cpp msgid "HTTP Host" @@ -19884,13 +19796,12 @@ msgid "HTTP Port" msgstr "" #: platform/javascript/export/export.cpp -#, fuzzy msgid "Use SSL" -msgstr "PoužÃt pÅ™ichycenÃ" +msgstr "PoužÃt SSL" #: platform/javascript/export/export.cpp msgid "SSL Key" -msgstr "" +msgstr "KlÃÄ SSL" #: platform/osx/export/codesign.cpp msgid "Can't get filesystem access." @@ -19952,9 +19863,8 @@ msgid "Invalid entitlements file." msgstr "Neplatná pÅ™Ãpona." #: platform/osx/export/codesign.cpp -#, fuzzy msgid "Invalid executable file." -msgstr "Neplatná pÅ™Ãpona." +msgstr "Neplatný spouÅ¡tÄ›cà soubor." #: platform/osx/export/codesign.cpp msgid "Can't resize signature load command." @@ -20442,7 +20352,7 @@ msgstr "" #: platform/osx/export/export.cpp msgid "Force Builtin Codesign" -msgstr "" +msgstr "Vynutit vestavÄ›ný codesign" #: platform/uwp/export/export.cpp #, fuzzy @@ -20580,6 +20490,8 @@ msgid "" "Godot's Mono version does not support the UWP platform. Use the standard " "build (no C# support) if you wish to target UWP." msgstr "" +"Mono verze Godotu nepodporuje platformu UWP. Použijte standartnà build (bez " +"podpory C#) pokud chcete použÃt platformu UWP." #: platform/uwp/export/export.cpp msgid "Invalid package short name." @@ -20635,7 +20547,7 @@ msgstr "Neplatné rozmÄ›ry obrázku uvÃtacà obrazovky (mÄ›ly by být 620x300). #: platform/uwp/export/export.cpp msgid "UWP" -msgstr "" +msgstr "UWP" #: platform/uwp/export/export.cpp platform/windows/export/export.cpp #, fuzzy @@ -20644,12 +20556,11 @@ msgstr "Signál" #: platform/uwp/export/export.cpp msgid "Debug Certificate" -msgstr "" +msgstr "Certifikát ladÄ›nÃ" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Debug Algorithm" -msgstr "Ladicà program" +msgstr "Algoritmus ladÄ›nÃ" #: platform/windows/export/export.cpp #, fuzzy @@ -21715,9 +21626,8 @@ msgid "Capping" msgstr "" #: scene/2d/line_2d.cpp -#, fuzzy msgid "Joint Mode" -msgstr "Režim ikony" +msgstr "Mód bodu" #: scene/2d/line_2d.cpp #, fuzzy @@ -22659,9 +22569,8 @@ msgid "Light Data" msgstr "S daty" #: scene/3d/bone_attachment.cpp scene/3d/physics_body.cpp -#, fuzzy msgid "Bone Name" -msgstr "Název uzlu:" +msgstr "Název kosti" #: scene/3d/camera.cpp msgid "Keep Aspect" @@ -23827,18 +23736,16 @@ msgid "Overlap Warning Threshold" msgstr "" #: scene/3d/room_manager.cpp -#, fuzzy msgid "Preview Camera" -msgstr "Náhled" +msgstr "Náhled kamery" #: scene/3d/room_manager.cpp msgid "Portal Depth Limit" msgstr "" #: scene/3d/room_manager.cpp -#, fuzzy msgid "Default Portal Margin" -msgstr "Nastavit okraj" +msgstr "Výchozà okraj portálu" #: scene/3d/room_manager.cpp #, fuzzy @@ -23875,6 +23782,9 @@ msgid "" "Room overlap detected, cameras may work incorrectly in overlapping area.\n" "Check output log for details." msgstr "" +"Bylo detekováno pÅ™ekrytà mÃstnostÃ, kamery nemusà fungovat správnÄ› v " +"pÅ™ekryvajÃcÃch oblastech.\n" +"Podrobnosti najdete ve výstupnÃm protokolu." #: scene/3d/room_manager.cpp msgid "" @@ -24370,14 +24280,12 @@ msgid "Zero Y" msgstr "Nula" #: scene/animation/skeleton_ik.cpp -#, fuzzy msgid "Root Bone" -msgstr "Název koÅ™enového uzlu" +msgstr "KoÅ™enová kost" #: scene/animation/skeleton_ik.cpp -#, fuzzy msgid "Tip Bone" -msgstr "Kosti" +msgstr "Å piÄková kost" #: scene/animation/skeleton_ik.cpp #, fuzzy @@ -24904,7 +24812,7 @@ msgstr "" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Caret" -msgstr "" +msgstr "StÅ™ÃÅ¡ka" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Blink" @@ -25554,7 +25462,7 @@ msgstr "Vynásobit %s" #: scene/main/scene_tree.cpp scene/resources/mesh_library.cpp #: scene/resources/shape_2d.cpp msgid "Shapes" -msgstr "" +msgstr "Tvary" #: scene/main/scene_tree.cpp msgid "Shape Color" @@ -25721,7 +25629,7 @@ msgstr "Levé lineárnÃ" #: scene/main/viewport.cpp msgid "Render Direct To Screen" -msgstr "" +msgstr "Vykreslovat pÅ™Ãmo na obrazovku" #: scene/main/viewport.cpp #, fuzzy @@ -26519,9 +26427,8 @@ msgid "Label Width" msgstr "Vlevo po celé výšce" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Screen Picker" -msgstr "Operátor screen." +msgstr "VýbÄ›r obrazovky" #: scene/resources/default_theme/default_theme.cpp #, fuzzy @@ -27600,9 +27507,8 @@ msgid "Bind" msgstr "Vazba" #: scene/resources/skin.cpp -#, fuzzy msgid "Bone" -msgstr "Kosti" +msgstr "Kost" #: scene/resources/sky.cpp #, fuzzy diff --git a/editor/translations/da.po b/editor/translations/da.po index bb158fcada..5a9e684e85 100644 --- a/editor/translations/da.po +++ b/editor/translations/da.po @@ -11471,7 +11471,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/de.po b/editor/translations/de.po index 61a5a51b9c..6d1c27e5b2 100644 --- a/editor/translations/de.po +++ b/editor/translations/de.po @@ -23,7 +23,7 @@ # Peter Friedland <peter_friedland@gmx.de>, 2016. # No need for a name <endoplasmatik@gmx.net>, 2016. # Sönke <me@eknoes.de>, 2018. -# So Wieso <sowieso@dukun.de>, 2016-2018, 2019, 2020, 2021, 2022. +# So Wieso <sowieso@dukun.de>, 2016-2018, 2019, 2020, 2021, 2022, 2023. # Tim Schellenberg <smwleod@gmail.com>, 2017. # Timo Schwarzer <account@timoschwarzer.com>, 2016-2018. # viernullvier <hannes.breul+github@gmail.com>, 2016. @@ -87,13 +87,14 @@ # Anonynonymouse <tom.spaine60388@gmail.com>, 2022. # Felix Bitsch <felix.a.bitsch@gmail.com>, 2022. # miguel <miguel-gonzalez@gmx.de>, 2022. +# Least Significant Bite <leastsignificantbite@proton.me>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-12-13 13:21+0000\n" -"Last-Translator: ‎ <artism90@googlemail.com>\n" +"PO-Revision-Date: 2023-01-09 20:42+0000\n" +"Last-Translator: So Wieso <sowieso@dukun.de>\n" "Language-Team: German <https://hosted.weblate.org/projects/godot-engine/" "godot/de/>\n" "Language: de\n" @@ -101,7 +102,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -482,7 +483,7 @@ msgstr "Gedrückt" #: core/os/input_event.cpp msgid "Scancode" -msgstr "Scancode" +msgstr "Tastencode" #: core/os/input_event.cpp msgid "Physical Scancode" @@ -3751,7 +3752,7 @@ msgstr "Hoch" #: editor/editor_network_profiler.cpp editor/editor_node.cpp #: scene/main/node.cpp scene/resources/default_theme/default_theme.cpp msgid "Node" -msgstr "Knoten" +msgstr "das Node" #: editor/editor_network_profiler.cpp msgid "Incoming RPC" @@ -11038,7 +11039,7 @@ msgstr "Hinten perspektivisch" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [Portale aktiv]" @@ -14308,17 +14309,15 @@ msgid "Invalid project path (changed anything?)." msgstr "Ungültiger Projektpfad (etwas geändert?)." #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." msgstr "" -"Die Datei project.godot im Projektpfad konnte nicht geladen werden (Fehler " -"%d). Sie könnte fehlen oder beschädigt sein." +"Projekt in ‚%s‘ konnte nicht geladen werden (Fehler %d). Es ist " +"möglicherweise nicht vorhanden oder beschädigt." #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "Projekt in ‚%s‘ kann nicht geöffnet werden." +msgstr "Projekt konnte nicht in ‚%s‘ gespeichert werden (Fehler %d)." #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -23255,14 +23254,12 @@ msgid "AABB" msgstr "AABB" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Sorting" -msgstr "Sortiere" +msgstr "Sortierung" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Use AABB Center" -msgstr "Ambient verwenden" +msgstr "AABB-Mittelpunkt verwenden" #: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp msgid "Geometry" diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 7b7bfd71cc..964eb46175 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -1,6 +1,6 @@ # LANGUAGE translation of the Godot Engine editor. -# Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. -# Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). +# Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). +# Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. # This file is distributed under the same license as the Godot source code. # # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. @@ -10564,7 +10564,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/el.po b/editor/translations/el.po index 98873c7d40..fe89b69334 100644 --- a/editor/translations/el.po +++ b/editor/translations/el.po @@ -18,13 +18,14 @@ # JessicaLukatz <jessicalukatz32038@gmail.com>, 2022. # Anthony V. <batmanplayer123@gmail.com>, 2022. # Anthony V. <anthonyv156@outlook.com>, 2022. +# Ilias Vasilakis <vaselas99@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-05-20 11:17+0000\n" -"Last-Translator: Anthony V. <anthonyv156@outlook.com>\n" +"PO-Revision-Date: 2023-01-15 13:34+0000\n" +"Last-Translator: Ilias Vasilakis <vaselas99@gmail.com>\n" "Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/" "el/>\n" "Language: el\n" @@ -32,7 +33,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -622,7 +623,7 @@ msgstr "Εμφάνιση όλων" #: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp #: scene/3d/label_3d.cpp scene/gui/text_edit.cpp scene/resources/texture.cpp msgid "Width" -msgstr "" +msgstr "Πλάτος" #: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp #: modules/gltf/gltf_node.cpp modules/opensimplex/noise_texture.cpp @@ -636,7 +637,7 @@ msgstr "Φως" #: core/project_settings.cpp msgid "Always On Top" -msgstr "" +msgstr "Πάντα στο επάνω μÎÏος" #: core/project_settings.cpp #, fuzzy @@ -804,7 +805,7 @@ msgstr "Απόδοση" #: scene/resources/multimesh.cpp servers/visual/visual_server_scene.cpp #: servers/visual_server.cpp msgid "Quality" -msgstr "" +msgstr "Ποιότητα" #: core/project_settings.cpp scene/gui/file_dialog.cpp #: scene/main/scene_tree.cpp scene/resources/navigation_mesh.cpp @@ -863,7 +864,7 @@ msgstr "" #: core/project_settings.cpp msgid "Compression Level" -msgstr "" +msgstr "Βαθμός Συμπίεσης" #: core/project_settings.cpp msgid "Window Log Size" @@ -1034,11 +1035,11 @@ msgstr "" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Elements" -msgstr "" +msgstr "ÎœÎγιστος αÏιθμός οπτικοποιήσημων στοιχείων" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Lights" -msgstr "" +msgstr "ÎœÎγιστος αÏιθμός Οπτικοποιήσημων Φωτών" #: drivers/gles3/rasterizer_scene_gles3.cpp #, fuzzy @@ -1081,7 +1082,7 @@ msgstr "" #: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp msgid "High Quality" -msgstr "" +msgstr "Υψηλή Ποιότητα" #: drivers/gles3/rasterizer_storage_gles3.cpp msgid "Blend Shape Max Buffer Size (KB)" @@ -1196,7 +1197,7 @@ msgstr "Ποσότητα:" #: editor/animation_track_editor.cpp main/main.cpp #: modules/mono/mono_gd/gd_mono.cpp msgid "Args" -msgstr "" +msgstr "ΟÏίσματα" #: editor/animation_track_editor.cpp editor/editor_settings.cpp #: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp @@ -2474,7 +2475,7 @@ msgstr "" #: editor/editor_asset_installer.cpp msgid "Contents of asset \"%s\" - No files conflict with your project:" -msgstr "" +msgstr "ΠεÏιεχόμενα Î ÏŒÏου \"%s\" - Καμία ΣÏγκÏουση αÏχείων στο ΈÏγο σου:" #: editor/editor_asset_installer.cpp msgid "Uncompressing Assets" @@ -2486,9 +2487,8 @@ msgid "The following files failed extraction from asset \"%s\":" msgstr "Η εξαγωγή των ακόλουθων αÏχείων από το πακÎτο απÎτυχε:" #: editor/editor_asset_installer.cpp -#, fuzzy msgid "(and %s more files)" -msgstr "Και %s αÏχεία ακόμα." +msgstr "Και %s αÏχεία ακόμα" #: editor/editor_asset_installer.cpp #, fuzzy @@ -2837,22 +2837,19 @@ msgstr "ΕπιλÎξτε" #: editor/editor_export.cpp msgid "Project export for platform:" -msgstr "" +msgstr "Εξαγωγή ΈÏγου για πλατφόÏμα:" #: editor/editor_export.cpp -#, fuzzy msgid "Completed with warnings." -msgstr "ΑντιγÏαφή διαδÏομής κόμβου" +msgstr "ΟλοκληÏώθηκε με Î Ïοειδοποιήσεις." #: editor/editor_export.cpp -#, fuzzy msgid "Completed successfully." -msgstr "Το πακÎτο εγκαταστάθηκε επιτυχώς!" +msgstr "Επιτυχής ΟλοκλήÏωση." #: editor/editor_export.cpp -#, fuzzy msgid "Failed." -msgstr "ΑπÎτυχε:" +msgstr "ΑπÎτυχε." #: editor/editor_export.cpp msgid "Storing File:" @@ -2877,14 +2874,12 @@ msgid "Cannot create file \"%s\"." msgstr "ΑδÏνατη η δημιουÏγία φακÎλου." #: editor/editor_export.cpp -#, fuzzy msgid "Failed to export project files." -msgstr "ΑπÎτυχε η εγγÏαφή σε αÏχείο:" +msgstr "ΑπÎτυχε η εξαγωγή αÏχείων ÎÏγου." #: editor/editor_export.cpp -#, fuzzy msgid "Can't open file to read from path \"%s\"." -msgstr "ΑδÏνατο το άνοιγμα αÏχείου για εγγÏαφή:" +msgstr "ΑδÏνατο το άνοιγμα αÏχείου για ανάγνωση απο το μονοπάτι \"%s\"." #: editor/editor_export.cpp #, fuzzy @@ -2962,9 +2957,8 @@ msgid "Release" msgstr "ΕλευθÎÏωση" #: editor/editor_export.cpp -#, fuzzy msgid "Binary Format" -msgstr "Τελεστής χÏώματος." +msgstr "Δυαδική ΜοÏφή" #: editor/editor_export.cpp msgid "64 Bits" @@ -3017,14 +3011,12 @@ msgid "Prepare Template" msgstr "ΔιαχείÏιση Î ÏοτÏπων" #: editor/editor_export.cpp platform/osx/export/export.cpp -#, fuzzy msgid "The given export path doesn't exist." -msgstr "Η δεδομÎνη διαδÏομή εξαγωγής δεν υπάÏχει:" +msgstr "Η δεδομÎνη διαδÏομή εξαγωγής δεν υπάÏχει." #: editor/editor_export.cpp platform/javascript/export/export.cpp -#, fuzzy msgid "Template file not found: \"%s\"." -msgstr "Δεν βÏÎθηκε αÏχείο Ï€ÏοτÏπου:" +msgstr "Δεν βÏÎθηκε το αÏχείο Ï€ÏοτÏπου: \"%s\"." #: editor/editor_export.cpp #, fuzzy @@ -3077,7 +3069,7 @@ msgstr "ΠλατφόÏμα Εισαγωγής" #: editor/editor_feature_profile.cpp msgid "Allows to view and edit 3D scenes." -msgstr "" +msgstr "ΕπιτÏÎπει την Ï€Ïοβολή και επεξεÏγασία Ï„Ïισδιάστατων σκηνών." #: editor/editor_feature_profile.cpp msgid "Allows to edit scripts using the integrated script editor." @@ -6103,9 +6095,8 @@ msgid "Bone Outline Color" msgstr "" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Outline Size" -msgstr "ÎœÎγεθος πεÏιγÏάμματος:" +msgstr "ÎœÎγεθος πεÏιγÏάμματος Κοκάλου" #: editor/editor_settings.cpp msgid "Viewport Border Color" @@ -10857,7 +10848,7 @@ msgstr "Î ÏοηγοÏμενη ΔÎσμη ΕνεÏγειών" #: editor/plugins/script_editor_plugin.cpp #: scene/resources/default_theme/default_theme.cpp msgid "File" -msgstr "ΑÏχείο" +msgstr "Φάκελος" #: editor/plugins/script_editor_plugin.cpp msgid "Open..." @@ -11366,7 +11357,7 @@ msgstr "Î Ïοοπτική" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" @@ -16732,15 +16723,15 @@ msgstr "ΧÏήση κουμπώματος" #: main/main.cpp msgid "Per Pixel Transparency" -msgstr "" +msgstr "Διαφάνεια ανα Πίξελ" #: main/main.cpp msgid "Allowed" -msgstr "" +msgstr "ΕπιτÏεπτό" #: main/main.cpp msgid "Intended Usage" -msgstr "" +msgstr "Î Ïοβλεπόμενη ΧÏήση" #: main/main.cpp #, fuzzy @@ -16754,7 +16745,7 @@ msgstr "Σφάλμα αποθήκευσης" #: main/main.cpp msgid "Threads" -msgstr "" +msgstr "Îήματα" #: main/main.cpp servers/physics_2d/physics_2d_server_wrap_mt.h #, fuzzy @@ -16767,7 +16758,7 @@ msgstr "" #: main/main.cpp msgid "Handheld" -msgstr "" +msgstr "ΧειÏός" #: main/main.cpp platform/javascript/export/export.cpp #: platform/uwp/export/export.cpp @@ -16799,7 +16790,7 @@ msgstr "" #: scene/gui/scroll_container.cpp scene/gui/text_edit.cpp scene/gui/tree.cpp #: scene/main/viewport.cpp scene/register_scene_types.cpp msgid "GUI" -msgstr "" +msgstr "ΓÏαφική Διεπαφή ΧÏήσης" #: main/main.cpp msgid "Drop Mouse On GUI Input Disabled" @@ -16811,7 +16802,7 @@ msgstr "" #: main/main.cpp msgid "Print FPS" -msgstr "" +msgstr "Δείξε ΚαÏΠανα ΔευτεÏόλεπτο" #: main/main.cpp msgid "Verbose stdout" @@ -16834,7 +16825,7 @@ msgstr "ΚαÏΠΕπιλογής" #: main/main.cpp msgid "Low Processor Mode" -msgstr "" +msgstr "ΛειτουÏγεία Χαμηλής ΧÏήσης ΕπεξεÏγαστή" #: main/main.cpp msgid "Delta Sync After Draw" @@ -16860,7 +16851,7 @@ msgstr "Σημείο" #: main/main.cpp msgid "Touch Delay" -msgstr "" +msgstr "ΚαθυστÎÏηση Επαφής" #: main/main.cpp servers/visual_server.cpp msgid "GLES3" @@ -16884,7 +16875,7 @@ msgstr "Εμφάνιση πεÏιβάλλοντος" #: main/main.cpp msgid "Default Clear Color" -msgstr "" +msgstr "Î ÏοκαθοÏισμÎνο ΧÏώμα ΚαθαÏίσματος" #: main/main.cpp msgid "Boot Splash" @@ -16897,11 +16888,11 @@ msgstr "Εμφάνιση Οστών" #: main/main.cpp msgid "Image" -msgstr "" +msgstr "Εικόνα" #: main/main.cpp msgid "Fullsize" -msgstr "" +msgstr "ΠλήÏης ÎœÎγεθος" #: main/main.cpp scene/resources/dynamic_font.cpp #, fuzzy @@ -16932,11 +16923,11 @@ msgstr "" #: main/main.cpp msgid "Emulate Touch From Mouse" -msgstr "" +msgstr "Î Ïοσομοίωση Αφής απο το Ποντίκι" #: main/main.cpp msgid "Emulate Mouse From Touch" -msgstr "" +msgstr "Î Ïοσομοίωση Î Î¿Î½Ï„Î¹ÎºÎ¹Î¿Ï Î±Ï€Î¿ Αφή" #: main/main.cpp #, fuzzy @@ -16974,11 +16965,11 @@ msgstr "Λήξη χÏÎ¿Î½Î¹ÎºÎ¿Ï Î¿Ïίου." #: main/main.cpp msgid "Runtime" -msgstr "" +msgstr "ΧÏόνος ΕκτÎλεσης" #: main/main.cpp msgid "Unhandled Exception Policy" -msgstr "" +msgstr "Πολιτική μη-χειÏιζόμενων ΕξαίÏεσεων" #: main/main.cpp #, fuzzy @@ -16988,7 +16979,7 @@ msgstr "ΕÏÏεση είδους κόμβου" #: main/main.cpp scene/gui/texture_progress.cpp #: scene/gui/viewport_container.cpp msgid "Stretch" -msgstr "" +msgstr "ΤÎντωμα" #: main/main.cpp #, fuzzy @@ -16997,11 +16988,11 @@ msgstr "ΕπιθεωÏητής" #: main/main.cpp msgid "Shrink" -msgstr "" +msgstr "Συστολή" #: main/main.cpp scene/main/scene_tree.cpp msgid "Auto Accept Quit" -msgstr "" +msgstr "Αυτόματη Αποδοχή Εξόδου" #: main/main.cpp scene/main/scene_tree.cpp #, fuzzy @@ -17015,11 +17006,11 @@ msgstr "Î Ïοσκόλληση σε ΠλευÏÎÏ‚ Κόμβου" #: main/main.cpp msgid "Dynamic Fonts" -msgstr "" +msgstr "ΔυναμικÎÏ‚ ΓÏαμματοσειÏÎÏ‚" #: main/main.cpp msgid "Use Oversampling" -msgstr "" +msgstr "ΧÏήση ΥπεÏδειγματοληψίας" #: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp msgid "Active Soft World" @@ -17052,7 +17043,7 @@ msgstr "ΕπιλογÎÏ‚" #: modules/csg/csg_shape.cpp msgid "Calculate Tangents" -msgstr "" +msgstr "Υπολογεισμός ΚαθÎτων" #: modules/csg/csg_shape.cpp #, fuzzy @@ -17110,7 +17101,7 @@ msgstr "Εμφάνιση Οδηγιών" #: modules/csg/csg_shape.cpp msgid "Cone" -msgstr "" +msgstr "Κώνος" #: modules/csg/csg_shape.cpp #, fuzzy @@ -17135,11 +17126,11 @@ msgstr "ΠολÏγωνα" #: modules/csg/csg_shape.cpp msgid "Spin Degrees" -msgstr "" +msgstr "Βαθμοί ΠεÏιστοφικής Κίνησης" #: modules/csg/csg_shape.cpp msgid "Spin Sides" -msgstr "" +msgstr "ΠλευÏÎÏ‚ ΠεÏιστÏοφικής Κίνησης" #: modules/csg/csg_shape.cpp #, fuzzy @@ -17337,7 +17328,7 @@ msgstr "ΔÎσμες ΕνεÏγειών" #: modules/gdscript/editor/gdscript_highlighter.cpp msgid "Function Definition Color" -msgstr "" +msgstr "ΧÏώμα Δήλωσης ΣυνάÏτησης" #: modules/gdscript/editor/gdscript_highlighter.cpp #, fuzzy @@ -17350,7 +17341,7 @@ msgstr "" #: modules/gdscript/gdscript.cpp msgid "Treat Warnings As Errors" -msgstr "" +msgstr "ΣυμπεÏιφοÏά σε Ï€Ïοειδοποιήσεις ως σφάλματα" #: modules/gdscript/gdscript.cpp msgid "Exclude Addons" @@ -17414,7 +17405,7 @@ msgstr "" #: modules/gdscript/language_server/gdscript_language_server.cpp msgid "Use Thread" -msgstr "" +msgstr "ΧÏήση Îήματος" #: modules/gltf/editor_scene_exporter_gltf_plugin.cpp #, fuzzy @@ -17639,11 +17630,11 @@ msgstr "" #: modules/gltf/gltf_spec_gloss.cpp msgid "Diffuse Factor" -msgstr "" +msgstr "Βαθμός Διάχυσης" #: modules/gltf/gltf_spec_gloss.cpp msgid "Gloss Factor" -msgstr "" +msgstr "Βαθμός Γυαλάδας" #: modules/gltf/gltf_spec_gloss.cpp #, fuzzy @@ -17704,11 +17695,11 @@ msgstr "Δυνατότητες" #: modules/gltf/gltf_state.cpp platform/uwp/export/export.cpp msgid "Images" -msgstr "" +msgstr "Εικόνες" #: modules/gltf/gltf_state.cpp msgid "Cameras" -msgstr "" +msgstr "ΚάμεÏες" #: modules/gltf/gltf_state.cpp servers/visual_server.cpp #, fuzzy @@ -17782,7 +17773,7 @@ msgstr "ΚÎντÏο" #: scene/2d/tile_map.cpp scene/3d/collision_object.cpp scene/3d/soft_body.cpp #: scene/resources/material.cpp msgid "Mask" -msgstr "" +msgstr "Μάσκα" #: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp #, fuzzy @@ -17932,7 +17923,7 @@ msgstr "" #: modules/lightmapper_cpu/lightmapper_cpu.cpp msgid "Preparing data structures" -msgstr "" +msgstr "Î Ïοετοιμασία δομών δεδομÎνων" #: modules/lightmapper_cpu/lightmapper_cpu.cpp #, fuzzy @@ -17966,19 +17957,19 @@ msgstr "Î Ïοετοιμασία Lightmaps" #: modules/lightmapper_cpu/register_types.cpp msgid "Low Quality Ray Count" -msgstr "" +msgstr "ΑÏιθμός Ακτινών Χαμηλής Ποιότητας" #: modules/lightmapper_cpu/register_types.cpp msgid "Medium Quality Ray Count" -msgstr "" +msgstr "ΑÏιθμός Ακτινών ÎœÎÏ„Ïιας Ποιότητας" #: modules/lightmapper_cpu/register_types.cpp msgid "High Quality Ray Count" -msgstr "" +msgstr "ΑÏιθμός Ακτινών Υψηλής Ποιότητας" #: modules/lightmapper_cpu/register_types.cpp msgid "Ultra Quality Ray Count" -msgstr "" +msgstr "ΑÏιθμός Ακτινών Ύψιστης Ποιότητας" #: modules/minimp3/audio_stream_mp3.cpp #: modules/minimp3/resource_importer_mp3.cpp @@ -17990,7 +17981,7 @@ msgstr "Μετατόπιση:" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "Eye Height" -msgstr "" +msgstr "Ύψος Ματιών" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "IOD" @@ -18133,7 +18124,7 @@ msgstr "" #: modules/opensimplex/noise_texture.cpp msgid "Noise" -msgstr "" +msgstr "ΘόÏυβος" #: modules/opensimplex/noise_texture.cpp #, fuzzy @@ -18142,11 +18133,11 @@ msgstr "Μετατόπιση ΠλÎγματος:" #: modules/opensimplex/open_simplex_noise.cpp msgid "Octaves" -msgstr "" +msgstr "Οκτάβες" #: modules/opensimplex/open_simplex_noise.cpp msgid "Period" -msgstr "" +msgstr "ΠεÏίοδος" #: modules/opensimplex/open_simplex_noise.cpp #, fuzzy @@ -18155,7 +18146,7 @@ msgstr "Î Ïοοπτική" #: modules/opensimplex/open_simplex_noise.cpp msgid "Lacunarity" -msgstr "" +msgstr "Κενότητα" #: modules/regex/regex.cpp msgid "Subject" @@ -18177,7 +18168,7 @@ msgstr "" #: modules/upnp/upnp.cpp msgid "Discover Local Port" -msgstr "" +msgstr "ΕÏÏεση Τοπικής ΘÏÏας" #: modules/upnp/upnp.cpp msgid "Discover IPv6" @@ -18740,26 +18731,24 @@ msgid "Mod %s" msgstr "Î Ïόσθεσε %s" #: modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "ShiftLeft %s" -msgstr "ΘÎσε %s" +msgstr "ΑÏιστεÏή μετατόπιση %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "ShiftRight %s" -msgstr "" +msgstr "Δεξιά μετατόπιση %s" #: modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "BitAnd %s" -msgstr "Î Ïόσθεσε %s" +msgstr "Λογικό Και %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitOr %s" -msgstr "" +msgstr "ΛογικόΗ %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitXor %s" -msgstr "" +msgstr "Î›Î¿Î³Î¹ÎºÏŒÎžÎ¿Ï %s" #: modules/visual_script/visual_script_func_nodes.cpp #, fuzzy @@ -18895,9 +18884,8 @@ msgid "Get Self" msgstr "Εαυτός" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "CustomNode" -msgstr "Αποκοπή κόμβων" +msgstr "" #: modules/visual_script/visual_script_nodes.cpp msgid "Custom node has no _step() method, can't process graph." @@ -18955,7 +18943,7 @@ msgstr "εσοδεία" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Wait" -msgstr "" +msgstr "ΠεÏίμενε" #: modules/visual_script/visual_script_yield_nodes.cpp #, fuzzy @@ -19605,10 +19593,11 @@ msgstr "" #: platform/android/export/export_plugin.cpp msgid "Invalid filename! Android APK requires the *.apk extension." msgstr "" +"Μή ΈγκυÏο όνομα αÏχείου! Το Android APK δÎχεται μόνο την .apk κατάληξη." #: platform/android/export/export_plugin.cpp msgid "Unsupported export format!" -msgstr "" +msgstr "Μη αποδεκτή μοÏφή εξαγωγής!" #: platform/android/export/export_plugin.cpp msgid "" @@ -19661,7 +19650,7 @@ msgstr "" #: platform/android/export/export_plugin.cpp msgid "Moving output" -msgstr "" +msgstr "Μετακίνηση της εξόδου" #: platform/android/export/export_plugin.cpp msgid "" @@ -21362,7 +21351,7 @@ msgstr "ΣυμπλήÏωση" #: scene/2d/canvas_item.cpp msgid "Show Behind Parent" -msgstr "" +msgstr "Δείξε πίσω απο τον ΓωνÎα" #: scene/2d/canvas_item.cpp #, fuzzy @@ -21377,7 +21366,7 @@ msgstr "Φως" #: scene/2d/canvas_item.cpp msgid "Use Parent Material" -msgstr "" +msgstr "ΧÏησιμποίησε το Υλικό του ΓονÎα" #: scene/2d/canvas_modulate.cpp msgid "" @@ -21422,6 +21411,8 @@ msgstr "Ένα άδειο ColisionPollygon2D δεν επηÏεάζει τη ÏƒÏ #: scene/2d/collision_polygon_2d.cpp msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode." msgstr "" +"Μή ÎγκυÏο πολÏγωνο. Î ÏÎπει να Ï€ÏοσδιοÏιστοÏν τουλάχιστον Ï„Ïία (3) σημεία για " +"τη δημιουÏγία στεÏÎµÎ¿Ï Î±Î½Ï„Î¹ÎºÎµÎ¹Î¼Îνου." #: scene/2d/collision_polygon_2d.cpp msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode." @@ -21499,7 +21490,7 @@ msgstr "Ρυθμίσεις:" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp msgid "Lifetime" -msgstr "" +msgstr "ΔιάÏκεια Ζωής" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp scene/main/timer.cpp @@ -21516,7 +21507,7 @@ msgstr "ΜετεπεξεÏγασία" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp msgid "Explosiveness" -msgstr "" +msgstr "ΕκÏηκτικότητα" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp @@ -21527,7 +21518,7 @@ msgstr "Τυχαία επανεκκίνηση (δευτεÏόλεπτα):" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp msgid "Lifetime Randomness" -msgstr "" +msgstr "Τυχαιότητα ΔιάÏκειας Ζωής" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp @@ -21543,7 +21534,7 @@ msgstr "" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp msgid "Drawing" -msgstr "" +msgstr "Σχεδίαση" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp @@ -21554,7 +21545,7 @@ msgstr "ΈÏγα" #: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/particles.cpp msgid "Draw Order" -msgstr "" +msgstr "ΣειÏά Σχεδίασης" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp @@ -21594,7 +21585,7 @@ msgstr "Κατευθήνσεις" #: scene/resources/particles_material.cpp #: servers/audio/effects/audio_effect_reverb.cpp msgid "Spread" -msgstr "" +msgstr "ΕÏÏος" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp @@ -21612,7 +21603,7 @@ msgstr "ΑÏχικοποιήστε" #: scene/resources/particles_material.cpp servers/physics_2d_server.cpp #: servers/physics_server.cpp msgid "Angular Velocity" -msgstr "" +msgstr "Γωνιακή ταχÏτητα" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp @@ -21623,7 +21614,7 @@ msgstr "ΑÏχικοποιήστε" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp msgid "Orbit Velocity" -msgstr "" +msgstr "ΤÏοχιακή ταχÏτητα" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp @@ -21651,12 +21642,12 @@ msgstr "ΔιαίÏεση ΚαμπÏλης" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp msgid "Radial Accel" -msgstr "" +msgstr "ΤÏοχιακή επιτάχυνση" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp msgid "Tangential Accel" -msgstr "" +msgstr "Γωνιακή επιτάχυνση" #: scene/2d/cpu_particles_2d.cpp scene/2d/joints_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/physics_body.cpp @@ -21664,12 +21655,12 @@ msgstr "" #: scene/resources/particles_material.cpp #: servers/audio/effects/audio_effect_reverb.cpp msgid "Damping" -msgstr "" +msgstr "Απόσβεση" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp msgid "Damping Random" -msgstr "" +msgstr "Τυχαιότητα Απόσβεσης" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp @@ -21680,12 +21671,12 @@ msgstr "ΔιαίÏεση ΚαμπÏλης" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp scene/3d/light.cpp #: scene/resources/particles_material.cpp msgid "Angle" -msgstr "" +msgstr "Γωνία" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp msgid "Angle Random" -msgstr "" +msgstr "Τυχαιότητα Γωνίας" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/particles_material.cpp @@ -21700,7 +21691,7 @@ msgstr "Ποσότητα:" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp msgid "Scale Amount Random" -msgstr "" +msgstr "Τυχαιότητα ΠοσoÏ ÎšÎ»Î¹Î¼Î¬ÎºÏ‰ÏƒÎ·Ï‚" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #, fuzzy @@ -21768,15 +21759,15 @@ msgstr "κλείσιμο καμπÏλης" #: scene/2d/joints_2d.cpp msgid "Node A and Node B must be PhysicsBody2Ds" -msgstr "" +msgstr "Ο Κόμβος Α και ο Κόμβος Î’ Ï€ÏÎπει να είναι του Ï„Ïπου PhysicsBody2Ds" #: scene/2d/joints_2d.cpp msgid "Node A must be a PhysicsBody2D" -msgstr "" +msgstr "Ο Κόμβος Α Ï€ÏÎπει να είναι του Ï„Ïπου PhysicsBody2D" #: scene/2d/joints_2d.cpp msgid "Node B must be a PhysicsBody2D" -msgstr "" +msgstr "Ο κόμβος Î’ Ï€ÏÎπει να είναι του Ï„Ïπου PhysicsBody2D" #: scene/2d/joints_2d.cpp msgid "Joint is not connected to two PhysicsBody2Ds" @@ -22206,7 +22197,7 @@ msgstr "ΛειτουÏγία Î ÏοτεÏαιότητας" #: scene/2d/particles_2d.cpp scene/3d/particles.cpp msgid "Process Material" -msgstr "" +msgstr "ΕπεξεÏγασία ΥλικοÏ" #: scene/2d/path_2d.cpp scene/3d/path.cpp scene/resources/sky.cpp #: scene/resources/texture.cpp @@ -22269,7 +22260,7 @@ msgstr "" #: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp msgid "Physics Material Override" -msgstr "" +msgstr "ΠαÏάκαμψη Î¥Î»Î¹ÎºÎ¿Ï Î¦Ï…ÏƒÎ¹ÎºÎ®Ï‚" #: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp #: scene/resources/world.cpp scene/resources/world_2d.cpp @@ -22460,11 +22451,11 @@ msgstr "" #: scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp scene/3d/ray_cast.cpp msgid "Areas" -msgstr "" +msgstr "Τοποθεσίες" #: scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp scene/3d/ray_cast.cpp msgid "Bodies" -msgstr "" +msgstr "Σώματα" #: scene/2d/remote_transform_2d.cpp msgid "Path property must point to a valid Node2D node to work." @@ -22511,11 +22502,11 @@ msgstr "" #: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp msgid "Hframes" -msgstr "" +msgstr "ΟÏιζόντια ΚαÏÎ" #: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp msgid "Vframes" -msgstr "" +msgstr "Κάθετα ΚαÏÎ" #: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp #, fuzzy @@ -22594,7 +22585,7 @@ msgstr "ΛειτουÏγία ΣÏγκÏουσης" #: scene/2d/tile_map.cpp msgid "Use Kinematic" -msgstr "" +msgstr "ΧÏήση ΚινηματικοÏ" #: scene/2d/touch_screen_button.cpp #, fuzzy @@ -22630,7 +22621,7 @@ msgstr "Επικόλληση κίνησης" #: scene/2d/visibility_notifier_2d.cpp scene/3d/visibility_notifier.cpp msgid "Freeze Bodies" -msgstr "" +msgstr "Πάγωμα Σωμάτων" #: scene/2d/visibility_notifier_2d.cpp #, fuzzy @@ -22666,11 +22657,11 @@ msgstr "Η ARVRCamera απαιτεί γονικό κόμβο ARVROrigin." #: scene/3d/arvr_nodes.cpp msgid "Controller ID" -msgstr "" +msgstr "ΑναγνωÏηστικό ΧειÏιστηÏίου" #: scene/3d/arvr_nodes.cpp servers/arvr/arvr_positional_tracker.cpp msgid "Rumble" -msgstr "" +msgstr "Δώνηση" #: scene/3d/arvr_nodes.cpp msgid "ARVRController must have an ARVROrigin node as its parent." @@ -22729,7 +22720,7 @@ msgstr "" #: scene/3d/audio_stream_player_3d.cpp msgid "Out Of Range Mode" -msgstr "" +msgstr "ΑπομακÏισμÎνη ΛειτουÏγεία" #: scene/3d/audio_stream_player_3d.cpp #, fuzzy @@ -22748,7 +22739,7 @@ msgstr "Κίνηση" #: scene/3d/audio_stream_player_3d.cpp msgid "Attenuation Filter" -msgstr "" +msgstr "ΦίλτÏο Απόσβεσης" #: scene/3d/audio_stream_player_3d.cpp #: servers/audio/effects/audio_effect_chorus.cpp @@ -22775,11 +22766,11 @@ msgstr "ΠακετάÏισμα" #: scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp #: scene/3d/reflection_probe.cpp msgid "Interior" -msgstr "" +msgstr "ΕσωτεÏικό" #: scene/3d/baked_lightmap.cpp msgid "Finding meshes and lights" -msgstr "" +msgstr "Î’Ïίσκοντας πλÎγματα και φώτα" #: scene/3d/baked_lightmap.cpp msgid "Preparing geometry (%d/%d)" @@ -22813,11 +22804,11 @@ msgstr "ΜαÏαφÎτια" #: scene/3d/baked_lightmap.cpp msgid "Tweaks" -msgstr "" +msgstr "ΜικÏοδιοÏθώσεις" #: scene/3d/baked_lightmap.cpp msgid "Bounces" -msgstr "" +msgstr "Πηδήματα" #: scene/3d/baked_lightmap.cpp msgid "Bounce Indirect Energy" @@ -22907,7 +22898,7 @@ msgstr "" #: scene/3d/camera.cpp scene/3d/light.cpp scene/3d/reflection_probe.cpp msgid "Cull Mask" -msgstr "" +msgstr "Μάσκα Αποκοπής" #: scene/3d/camera.cpp #, fuzzy @@ -22921,7 +22912,7 @@ msgstr "ΈÏγο" #: scene/3d/camera.cpp msgid "FOV" -msgstr "" +msgstr "Οπτικό Πεδίο" #: scene/3d/camera.cpp #, fuzzy @@ -22935,7 +22926,7 @@ msgstr "ΠλησιÎστεÏη" #: scene/3d/camera.cpp msgid "Far" -msgstr "" +msgstr "ΜακÏιά" #: scene/3d/camera.cpp scene/3d/collision_polygon.cpp scene/3d/spring_arm.cpp #: scene/gui/control.cpp scene/resources/default_theme/default_theme.cpp @@ -22952,7 +22943,7 @@ msgstr "ΠεÏικοπή πάνω" #: scene/3d/collision_object.cpp scene/3d/soft_body.cpp msgid "Ray Pickable" -msgstr "" +msgstr "ΕπιλÎξημη Ακτίνα" #: scene/3d/collision_object.cpp #, fuzzy @@ -23068,7 +23059,7 @@ msgstr "ΑπενεÏγοποιημÎνο Στοιχείο" #: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp msgid "Flatness" -msgstr "" +msgstr "Ομαλότητα" #: scene/3d/cull_instance.cpp servers/visual_server.cpp #, fuzzy @@ -23086,7 +23077,7 @@ msgstr "" #: scene/3d/cull_instance.cpp msgid "Allow Merging" -msgstr "" +msgstr "ΕπίτÏεψε Συγχώνευση" #: scene/3d/cull_instance.cpp #, fuzzy @@ -23118,7 +23109,7 @@ msgstr "" #: scene/3d/gi_probe.cpp msgid "Subdiv" -msgstr "" +msgstr "ΥποδιαίÏεση" #: scene/3d/gi_probe.cpp #, fuzzy @@ -23137,7 +23128,7 @@ msgstr "ΚοÏμπωμα στα εικονοστοιχεία" #: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp msgid "Billboard" -msgstr "" +msgstr "Πινακίδα" #: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp #, fuzzy @@ -23146,11 +23137,11 @@ msgstr "Î ÏόγÏαμμα Σκίασης" #: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp msgid "Double Sided" -msgstr "" +msgstr "ΔÏο Όψεων" #: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp msgid "No Depth Test" -msgstr "" +msgstr "ΧωÏίς Έλεγχο Βάθους" #: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp #, fuzzy @@ -23289,7 +23280,7 @@ msgstr "" #: scene/3d/light.cpp msgid "Spot" -msgstr "" +msgstr "Î ÏοβολÎας" #: scene/3d/light.cpp #, fuzzy @@ -23349,7 +23340,7 @@ msgstr "" #: scene/3d/occluder.cpp msgid "No shape is set." -msgstr "" +msgstr "Δεν Îχει επιλεχθεί Σχήμα." #: scene/3d/occluder.cpp msgid "Only uniform scales are supported." @@ -23452,15 +23443,15 @@ msgstr "ΓÏαμμική" #: scene/3d/physics_body.cpp msgid "Angular X" -msgstr "" +msgstr "Γωνιώδης Χ" #: scene/3d/physics_body.cpp msgid "Angular Y" -msgstr "" +msgstr "Γωνιώδης Î¥" #: scene/3d/physics_body.cpp msgid "Angular Z" -msgstr "" +msgstr "Γωνιώδης Ζ" #: scene/3d/physics_body.cpp #, fuzzy @@ -23568,15 +23559,15 @@ msgstr "Κίνηση" #: scene/3d/physics_body.cpp msgid "X" -msgstr "" +msgstr "Χ" #: scene/3d/physics_body.cpp msgid "Y" -msgstr "" +msgstr "Î¥" #: scene/3d/physics_body.cpp msgid "Z" -msgstr "" +msgstr "Ζ" #: scene/3d/physics_body.cpp #, fuzzy @@ -23685,7 +23676,7 @@ msgstr "Αλλαγη ΠαÏαμÎÏ„Ïου" #: scene/3d/physics_joint.cpp msgid "Angular Limit" -msgstr "" +msgstr "Γωνιώδης ÎÏιο" #: scene/3d/physics_joint.cpp #, fuzzy @@ -23699,7 +23690,7 @@ msgstr "Πεζά" #: scene/3d/physics_joint.cpp msgid "Motor" -msgstr "" +msgstr "ΜοτÎÏ" #: scene/3d/physics_joint.cpp #, fuzzy @@ -23783,19 +23774,19 @@ msgstr "ΓÏαμμική" #: scene/3d/physics_joint.cpp msgid "Equilibrium Point" -msgstr "" +msgstr "ÎœÎÏος ΙσοÏÏοπείας" #: scene/3d/physics_joint.cpp msgid "Angular Limit X" -msgstr "" +msgstr "Γωνιώδης ÎÏιο Χ" #: scene/3d/physics_joint.cpp msgid "Angular Motor X" -msgstr "" +msgstr "Γωνιώδης ΜοτÎÏ Î§" #: scene/3d/physics_joint.cpp msgid "Angular Spring X" -msgstr "" +msgstr "Γωνιώδης ΕλατήÏιο Χ" #: scene/3d/physics_joint.cpp #, fuzzy @@ -23814,15 +23805,15 @@ msgstr "ΓÏαμμική" #: scene/3d/physics_joint.cpp msgid "Angular Limit Y" -msgstr "" +msgstr "Γωνιώδης ÎÏιο Î¥" #: scene/3d/physics_joint.cpp msgid "Angular Motor Y" -msgstr "" +msgstr "Γωνιώδης ΜοτÎÏ Î¥" #: scene/3d/physics_joint.cpp msgid "Angular Spring Y" -msgstr "" +msgstr "Γωνιώδης ΕλατήÏιο Î¥" #: scene/3d/physics_joint.cpp #, fuzzy @@ -23841,15 +23832,15 @@ msgstr "ΓÏαμμική" #: scene/3d/physics_joint.cpp msgid "Angular Limit Z" -msgstr "" +msgstr "Γωνιώδης ÎÏιο Ζ" #: scene/3d/physics_joint.cpp msgid "Angular Motor Z" -msgstr "" +msgstr "Γωνιώδης ΜοτÎÏ Î–" #: scene/3d/physics_joint.cpp msgid "Angular Spring Z" -msgstr "" +msgstr "Γωνιώδης ΕλατήÏιο Ζ" #: scene/3d/portal.cpp msgid "The RoomManager should not be a child or grandchild of a Portal." @@ -23870,7 +23861,7 @@ msgstr "ΕπιστÏοφή" #: scene/3d/portal.cpp scene/resources/occluder_shape_polygon.cpp msgid "Two Way" -msgstr "" +msgstr "Διπλής ΚατεÏθυνσης" #: scene/3d/portal.cpp #, fuzzy @@ -23903,7 +23894,7 @@ msgstr "Αποσφαλματωτής" #: scene/3d/ray_cast.cpp scene/resources/style_box.cpp msgid "Thickness" -msgstr "" +msgstr "Πάχος" #: scene/3d/reflection_probe.cpp scene/main/viewport.cpp #, fuzzy @@ -23950,7 +23941,7 @@ msgstr "" #: scene/3d/room.cpp msgid "A Room cannot have another Room as a child or grandchild." -msgstr "" +msgstr "Ενα δωμάτιο δεν μποÏεί να Îχει άλλο δωμάτιο ως παιδί ή εγγόνι." #: scene/3d/room.cpp msgid "The RoomManager should not be placed inside a Room." @@ -23976,7 +23967,7 @@ msgstr "" #: scene/3d/room.cpp msgid "Bound" -msgstr "" +msgstr "ÎŒÏιο" #: scene/3d/room_group.cpp #, fuzzy @@ -24019,7 +24010,7 @@ msgstr "ΕνÎÏγεια" #: scene/3d/room_manager.cpp msgid "Roomlist" -msgstr "" +msgstr "Λίστα Δωματίων" #: scene/3d/room_manager.cpp servers/visual_server.cpp #, fuzzy @@ -24038,7 +24029,7 @@ msgstr "ΑÏχείο ZIP" #: scene/3d/room_manager.cpp servers/visual_server.cpp msgid "Gameplay" -msgstr "" +msgstr "Παιχνίδι" #: scene/3d/room_manager.cpp #, fuzzy @@ -25147,7 +25138,7 @@ msgstr "" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Caret" -msgstr "" +msgstr "ΚαÏÎ" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Blink" @@ -26123,7 +26114,7 @@ msgstr "" #: scene/resources/default_theme/default_theme.cpp msgid "Panel" -msgstr "" +msgstr "Πλαίσιο" #: scene/resources/default_theme/default_theme.cpp #, fuzzy @@ -26162,7 +26153,7 @@ msgstr "Επανάληψη κίνησης" #: scene/resources/default_theme/default_theme.cpp msgid "Arrow" -msgstr "" +msgstr "Î’Îλος" #: scene/resources/default_theme/default_theme.cpp #, fuzzy @@ -27148,7 +27139,7 @@ msgstr "Αποσφαλμάτωση ÎšÎ±Î½Î±Î»Î¹Î¿Ï UV" #: scene/resources/environment.cpp msgid "Blur" -msgstr "" +msgstr "Θόλωση" #: scene/resources/environment.cpp msgid "Edge Sharpness" @@ -27770,7 +27761,7 @@ msgstr "" #: scene/resources/physics_material.cpp msgid "Absorbent" -msgstr "" +msgstr "ΑποÏÏοφητικός" #: scene/resources/plane_shape.cpp #, fuzzy @@ -27815,7 +27806,7 @@ msgstr "Πάνω Δεξιά" #: scene/resources/primitive_meshes.cpp msgid "Is Hemisphere" -msgstr "" +msgstr "Είναι ΗμισφαίÏιο" #: scene/resources/primitive_meshes.cpp #, fuzzy @@ -27824,11 +27815,11 @@ msgstr "ΔιαίÏεση ΚαμπÏλης" #: scene/resources/ray_shape.cpp scene/resources/segment_shape_2d.cpp msgid "Slips On Slope" -msgstr "" +msgstr "ΓλυστÏάει σε Κλίση" #: scene/resources/segment_shape_2d.cpp msgid "A" -msgstr "" +msgstr "Α" #: scene/resources/shape_2d.cpp msgid "Custom Solver Bias" @@ -27856,7 +27847,7 @@ msgstr "ÎœÎγεθος πεÏιγÏάμματος:" #: scene/resources/sky.cpp msgid "Panorama" -msgstr "" +msgstr "ΠανόÏαμα" #: scene/resources/sky.cpp #, fuzzy @@ -27890,15 +27881,15 @@ msgstr "Αντικατάσταση" #: scene/resources/sky.cpp msgid "Longitude" -msgstr "" +msgstr "ΓεωγÏαφικό Μήκος" #: scene/resources/sky.cpp msgid "Angle Min" -msgstr "" +msgstr "Ελάχιστη Γωνία" #: scene/resources/sky.cpp msgid "Angle Max" -msgstr "" +msgstr "ÎœÎγιστη Γωνία" #: scene/resources/style_box.cpp #, fuzzy @@ -27912,7 +27903,7 @@ msgstr "Ανάπτυξη Όλων" #: scene/resources/style_box.cpp msgid "Skew" -msgstr "" +msgstr "Λοξότητα" #: scene/resources/style_box.cpp #, fuzzy @@ -27921,7 +27912,7 @@ msgstr "Αλλαγή ΕσωτεÏική Ακτίνας ΤόÏου" #: scene/resources/style_box.cpp msgid "Corner Detail" -msgstr "" +msgstr "ΛεπτομÎÏεια Γωνίας" #: scene/resources/style_box.cpp msgid "Anti Aliasing" @@ -28024,9 +28015,8 @@ msgid "Depth Draw" msgstr "ÎœÎθοδος παÏεμβολής" #: scene/resources/visual_shader.cpp -#, fuzzy msgid "Cull" -msgstr "ΛειτουÏγία ΧάÏακα" +msgstr "Αποκοπή" #: scene/resources/visual_shader.cpp #, fuzzy @@ -28260,11 +28250,11 @@ msgstr "" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 1" -msgstr "" +msgstr "Πάτησε 1" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 2" -msgstr "" +msgstr "Πάτησε 2" #: servers/audio/effects/audio_effect_delay.cpp #: servers/audio/effects/audio_effect_phaser.cpp @@ -28326,7 +28316,7 @@ msgstr "" #: servers/audio/effects/audio_effect_pitch_shift.cpp msgid "Oversampling" -msgstr "" +msgstr "ΥπεÏδειγματοληψία" #: servers/audio/effects/audio_effect_pitch_shift.cpp #: servers/audio/effects/audio_effect_spectrum_analyzer.cpp diff --git a/editor/translations/en_Shaw.po b/editor/translations/en_Shaw.po index 60caed0d9d..16e474d82d 100644 --- a/editor/translations/en_Shaw.po +++ b/editor/translations/en_Shaw.po @@ -10615,7 +10615,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/eo.po b/editor/translations/eo.po index 04205e10d6..4ed8103686 100644 --- a/editor/translations/eo.po +++ b/editor/translations/eo.po @@ -11199,7 +11199,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/es.po b/editor/translations/es.po index 5d683058c3..9e1868e4f9 100644 --- a/editor/translations/es.po +++ b/editor/translations/es.po @@ -14,7 +14,7 @@ # Diego López <diegodario21@gmail.com>, 2017. # eon-s <emanuel.segretin@gmail.com>, 2018, 2019, 2020. # Gustavo Leon <gleondiaz@gmail.com>, 2017-2018. -# Javier Ocampos <xavier.ocampos@gmail.com>, 2018, 2019, 2020, 2021, 2022. +# Javier Ocampos <xavier.ocampos@gmail.com>, 2018, 2019, 2020, 2021, 2022, 2023. # Jose Maria Martinez <josemar1992@hotmail.com>, 2018. # Juan Quiroga <juanquiroga9@gmail.com>, 2017. # Kiji Pixel <raccoon.fella@gmail.com>, 2017. @@ -90,14 +90,15 @@ # M3CG <cgmario1999@gmail.com>, 2022. # Chalan <Valentin06ch@outlook.com>, 2022. # Luis Miguel Soto Sánchez <luismiguelsoto@jerez.es>, 2022. -# Victor Stancioiu <victorstancioiu@gmail.com>, 2022. +# Victor Stancioiu <victorstancioiu@gmail.com>, 2022, 2023. +# Daniel Miranda <danmiranda@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-16 22:47+0000\n" -"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n" +"PO-Revision-Date: 2023-01-20 10:19+0000\n" +"Last-Translator: Daniel Miranda <danmiranda@gmail.com>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/" "godot/es/>\n" "Language: es\n" @@ -105,7 +106,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -11041,7 +11042,7 @@ msgstr "Perspectiva Trasera" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portales activos]" @@ -14308,17 +14309,15 @@ msgid "Invalid project path (changed anything?)." msgstr "La ruta del proyecto no es correcta (¿has cambiado algo?)." #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." msgstr "" -"No se pudo cargar project.godot desde la ruta de proyecto (error %d). La " -"ruta no existe o está corrupta." +"No se pudo cargar el proyecto desde la ruta '%s' (error %d). La ruta no " +"existe o está corrupta." #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "No se puede abrir el proyecto en '%s'." +msgstr "No se pudo guardar el proyecto en '%s' (error %d)." #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -22304,7 +22303,7 @@ msgstr "" #: scene/3d/mesh_instance.cpp msgid "Transform Normals" -msgstr "Transformar Normales" +msgstr "Normales de Transformación" #: scene/3d/navigation.cpp msgid "" @@ -23243,14 +23242,12 @@ msgid "AABB" msgstr "AABB" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Sorting" msgstr "Ordenar" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Use AABB Center" -msgstr "Usar Ambiente" +msgstr "Usar Centro de AABB" #: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp msgid "Geometry" @@ -25064,7 +25061,7 @@ msgstr "Marcar" #: scene/resources/default_theme/default_theme.cpp msgid "Updown" -msgstr "" +msgstr "Reducción" #: scene/resources/default_theme/default_theme.cpp msgid "Scaleborder Size" @@ -25544,11 +25541,11 @@ msgstr "Grados de Rotación del Cielo" #: scene/resources/environment.cpp msgid "Canvas Max Layer" -msgstr "" +msgstr "Max de Capas del Lienzo" #: scene/resources/environment.cpp scene/resources/texture.cpp msgid "Camera Feed ID" -msgstr "" +msgstr "Feed ID de la Cámara" #: scene/resources/environment.cpp msgid "Ambient Light" @@ -25688,7 +25685,7 @@ msgstr "Nitidez de Borde" #: scene/resources/environment.cpp msgid "DOF Far Blur" -msgstr "" +msgstr "DOF Desenfoque Lejano" #: scene/resources/environment.cpp scene/resources/material.cpp msgid "Distance" @@ -25700,7 +25697,7 @@ msgstr "Transición" #: scene/resources/environment.cpp msgid "DOF Near Blur" -msgstr "" +msgstr "DOF Desenfoque Cercano" #: scene/resources/environment.cpp msgid "Glow" @@ -25760,7 +25757,7 @@ msgstr "Escala HDR" #: scene/resources/environment.cpp msgid "Bicubic Upscale" -msgstr "" +msgstr "Escala Bicúbica Superior" #: scene/resources/environment.cpp msgid "Adjustments" @@ -25816,7 +25813,7 @@ msgstr "Siguiente Paso" #: scene/resources/material.cpp msgid "Use Shadow To Opacity" -msgstr "" +msgstr "Usar Sombra para Opacidad" #: scene/resources/material.cpp msgid "Unshaded" @@ -26655,15 +26652,15 @@ msgstr "Mezcla" #: servers/audio/effects/audio_effect_compressor.cpp msgid "Sidechain" -msgstr "" +msgstr "Sidechain" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 1" -msgstr "Toque 1" +msgstr "Tap 1" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 2" -msgstr "Toque 2" +msgstr "Tap 2" #: servers/audio/effects/audio_effect_delay.cpp #: servers/audio/effects/audio_effect_phaser.cpp @@ -26681,7 +26678,7 @@ msgstr "Pre-Ganancia" #: servers/audio/effects/audio_effect_distortion.cpp msgid "Keep Hf Hz" -msgstr "Mantener Hz Altas" +msgstr "Mantener Hf Hz" #: servers/audio/effects/audio_effect_distortion.cpp msgid "Drive" @@ -26697,19 +26694,19 @@ msgstr "Resonancia" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Ceiling dB" -msgstr "dB Tope" +msgstr "LÃmite de dB" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Threshold dB" -msgstr "Umbral dB" +msgstr "Umbral de dB" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Soft Clip dB" -msgstr "" +msgstr "Soft Clip dB" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Soft Clip Ratio" -msgstr "" +msgstr "Soft Clip Ratio" #: servers/audio/effects/audio_effect_phaser.cpp msgid "Range Min Hz" @@ -26721,7 +26718,7 @@ msgstr "Rango Hz Máximo" #: servers/audio/effects/audio_effect_pitch_shift.cpp msgid "Oversampling" -msgstr "Sobremuestreo" +msgstr "Oversampling" #: servers/audio/effects/audio_effect_pitch_shift.cpp #: servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -26730,7 +26727,7 @@ msgstr "Tamaño de FFT" #: servers/audio/effects/audio_effect_reverb.cpp msgid "Predelay" -msgstr "" +msgstr "Retraso" #: servers/audio/effects/audio_effect_reverb.cpp msgid "Msec" @@ -27050,7 +27047,7 @@ msgstr "" #: servers/visual_server.cpp msgid "Disable For Vendors" -msgstr "" +msgstr "Deshabilitar para Proveedores" #: servers/visual_server.cpp msgid "Anisotropic Filter Level" @@ -27182,7 +27179,7 @@ msgstr "Usar PVS Simple" #: servers/visual_server.cpp msgid "PVS Logging" -msgstr "" +msgstr "Registro de PVS" #: servers/visual_server.cpp msgid "Use Signals" diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po index fdb6b4f00d..24d38e14a7 100644 --- a/editor/translations/es_AR.po +++ b/editor/translations/es_AR.po @@ -22,13 +22,14 @@ # emnrx <emanuelermancia@gmail.com>, 2022. # Mau_Restor <restor@gmail.com>, 2022. # Leonardo MartÃnez <leonardomartinez85@gmail.com>, 2022. +# LR <nancok@tuta.io>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-26 14:36+0000\n" -"Last-Translator: emnrx <emanuelermancia@gmail.com>\n" +"PO-Revision-Date: 2023-01-01 05:48+0000\n" +"Last-Translator: LR <nancok@tuta.io>\n" "Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/" "godot-engine/godot/es_AR/>\n" "Language: es_AR\n" @@ -36,7 +37,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -286,11 +287,11 @@ msgstr "" #: core/io/packet_peer.cpp msgid "Input Buffer Max Size" -msgstr "" +msgstr "Tamaño maximo del bufer de entrada" #: core/io/packet_peer.cpp msgid "Output Buffer Max Size" -msgstr "" +msgstr "Tamaño maximo del buffer de salida" #: core/io/packet_peer.cpp msgid "Stream Peer" @@ -505,8 +506,9 @@ msgid "Strength" msgstr "Fuerza" #: core/os/input_event.cpp +#, fuzzy msgid "Delta" -msgstr "" +msgstr "Delta" #: core/os/input_event.cpp msgid "Channel" @@ -721,7 +723,7 @@ msgstr "Superior Derecha" #: core/project_settings.cpp msgid "UI Up" -msgstr "" +msgstr "Interfaz Arriba" #: core/project_settings.cpp #, fuzzy @@ -735,7 +737,7 @@ msgstr "Página: " #: core/project_settings.cpp msgid "UI Page Down" -msgstr "" +msgstr "Interfaz Bajar Pagina" #: core/project_settings.cpp msgid "UI Home" @@ -1013,7 +1015,7 @@ msgstr "Usar Muestreo Bicúbico" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Elements" -msgstr "" +msgstr "Cantidad Maxima de Elementos Renderizables" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Lights" @@ -11251,7 +11253,7 @@ msgstr "Perspectiva Trasera" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portales activos]" diff --git a/editor/translations/et.po b/editor/translations/et.po index dc36ae0b94..c08335ed4f 100644 --- a/editor/translations/et.po +++ b/editor/translations/et.po @@ -8,19 +8,20 @@ # René <renepiik@gmail.com>, 2020. # Kritzmensch <streef.gtx@gmail.com>, 2021, 2022. # dogyx <aaronloit@zohomail.eu>, 2022. +# Oskar U <oskar.unn2003@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-09-16 07:12+0000\n" -"Last-Translator: dogyx <aaronloit@zohomail.eu>\n" +"PO-Revision-Date: 2023-01-08 09:47+0000\n" +"Last-Translator: Oskar U <oskar.unn2003@gmail.com>\n" "Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/" "godot/et/>\n" "Language: et\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.14.1-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -9377,18 +9378,18 @@ msgstr "Lülita jagamisrežiim sisse/välja" #: scene/gui/rich_text_label.cpp scene/gui/text_edit.cpp #: scene/resources/primitive_meshes.cpp msgid "Text" -msgstr "" +msgstr "Tekst" #: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp main/main.cpp #: platform/osx/export/export.cpp platform/windows/export/export.cpp #: scene/gui/button.cpp scene/gui/item_list.cpp msgid "Icon" -msgstr "" +msgstr "Ikoon" #: editor/plugins/item_list_editor_plugin.cpp msgid "ID" -msgstr "" +msgstr "ID" #: editor/plugins/item_list_editor_plugin.cpp #: scene/resources/default_theme/default_theme.cpp @@ -10857,7 +10858,7 @@ msgstr "Perspektiiv" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/eu.po b/editor/translations/eu.po index 79da3d56fb..bfd4302fa8 100644 --- a/editor/translations/eu.po +++ b/editor/translations/eu.po @@ -10820,7 +10820,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/fa.po b/editor/translations/fa.po index ad2a56e408..eb6c113057 100644 --- a/editor/translations/fa.po +++ b/editor/translations/fa.po @@ -28,7 +28,7 @@ # Aryan Azadeh <aryan@azadeh.email>, 2022. # Mitsuha Miamizu <mitsuha.miamizu4444@gmail.com>, 2022. # LordProfo <nimaentity30@gmail.com>, 2022. -# LordProfo (Nima) <nimaentity30@gmail.com>, 2022. +# LordProfo (Nima) <nimaentity30@gmail.com>, 2022, 2023. # John Smith <pkafsharix@gmail.com>, 2022. # Ali Jafari <ali.jafari.sn@gmail.com>, 2022. # Ali Almasi <A710almasi@gmail.com>, 2022. @@ -38,8 +38,8 @@ msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-16 22:47+0000\n" -"Last-Translator: 2g.2d.2t <2g.2d.2t@gmail.com>\n" +"PO-Revision-Date: 2023-01-01 05:48+0000\n" +"Last-Translator: LordProfo (Nima) <nimaentity30@gmail.com>\n" "Language-Team: Persian <https://hosted.weblate.org/projects/godot-engine/" "godot/fa/>\n" "Language: fa\n" @@ -47,7 +47,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -2901,7 +2901,7 @@ msgstr "انتخاب Øالت" #: editor/editor_export.cpp msgid "BPTC" -msgstr "" +msgstr "بی‌پی‌تی‌سی (BPTC)" #: editor/editor_export.cpp platform/osx/export/export.cpp msgid "S3TC" @@ -2909,11 +2909,11 @@ msgstr "S3TC" #: editor/editor_export.cpp platform/osx/export/export.cpp msgid "ETC" -msgstr "ای‌تی‌سی" +msgstr "ئی‌تی‌سی (ETC)" #: editor/editor_export.cpp platform/osx/export/export.cpp msgid "ETC2" -msgstr "ای‌تی‌سی‌۲" +msgstr "ئی‌تی‌سی‌۲ (ETC2)" #: editor/editor_export.cpp msgid "No BPTC Fallbacks" @@ -2964,7 +2964,7 @@ msgstr "تبدیل منابع متنی به دوتایی هنگام خروجی" #: editor/editor_feature_profile.cpp msgid "3D Editor" -msgstr "ویرایشگر 3بعدی" +msgstr "ویرایشگر ۳بعدی" #: editor/editor_feature_profile.cpp msgid "Script Editor" @@ -3801,13 +3801,15 @@ msgstr "ایجاد بند انگشتی" #: editor/editor_node.cpp msgid "This operation can't be done without a tree root." -msgstr "" +msgstr "این عمل را نمی‌توان بدون tree root انجام داد." #: editor/editor_node.cpp msgid "" "This scene can't be saved because there is a cyclic instancing inclusion.\n" "Please resolve it and then attempt to save again." msgstr "" +"این صØنه را نمی‌توان ذخیره کرد زیرا یک شامل نمونه‌سازی چرخه‌ای وجود دارد.\n" +" لطÙاً آن را ØÙ„ کنید Ùˆ سپس دوباره سعی کنید ذخیره کنید." #: editor/editor_node.cpp msgid "" @@ -3873,6 +3875,9 @@ msgid "" "Please read the documentation relevant to importing scenes to better " "understand this workflow." msgstr "" +"این منبع متعلق به صØنه‌ای است Ú©Ù‡ ایمپورت شده است، بنابراین قابل ویرایش نیست.\n" +" لطÙاً اسناد مربوط به وارد کردن صØنه‌ها را بخوانید تا این گردش کار را بهتر درک " +"کنید." #: editor/editor_node.cpp msgid "" @@ -6913,7 +6918,7 @@ msgstr "" #: editor/import/editor_import_collada.cpp msgid "Collada" -msgstr "" +msgstr "کولادا" #: editor/import/editor_import_collada.cpp msgid "Use Ambient" @@ -11203,7 +11208,7 @@ msgstr "" msgid " [auto]" msgstr " [خودکار]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" @@ -17129,9 +17134,8 @@ msgid "Add an architecture entry" msgstr "" #: modules/gdnative/gdnative_library_editor_plugin.cpp -#, fuzzy msgid "GDNativeLibrary" -msgstr "صادکردن Ùایل کتابخانه ای" +msgstr "کتابخانهٔ جی‌دی‌نÙیتیو" #: modules/gdnative/gdnative_library_singleton_editor.cpp msgid "Enabled GDNative Singleton" @@ -18580,25 +18584,24 @@ msgid "Mod %s" msgstr "" #: modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "ShiftLeft %s" -msgstr "تنظیم %s" +msgstr "ShiftLeft %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "ShiftRight %s" -msgstr "" +msgstr "ShiftRight %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitAnd %s" -msgstr "" +msgstr "BitAnd %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitOr %s" -msgstr "" +msgstr "BitOr %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitXor %s" -msgstr "" +msgstr "BitXor %s" #: modules/visual_script/visual_script_func_nodes.cpp #, fuzzy @@ -18730,9 +18733,8 @@ msgid "Get Self" msgstr "" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "CustomNode" -msgstr "ساختن گره" +msgstr "نود سÙارشی" #: modules/visual_script/visual_script_nodes.cpp msgid "Custom node has no _step() method, can't process graph." @@ -18748,9 +18750,8 @@ msgstr "" "(error) باشد." #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "SubCall" -msgstr "Ùراخوانی" +msgstr "ساب‌کال" #: modules/visual_script/visual_script_nodes.cpp scene/gui/graph_node.cpp msgid "Title" @@ -18791,7 +18792,7 @@ msgstr "" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Wait" -msgstr "" +msgstr "صبرکردن" #: modules/visual_script/visual_script_yield_nodes.cpp #, fuzzy @@ -20516,7 +20517,7 @@ msgstr "انتقال را در انیمیشن تغییر بده" #: platform/uwp/export/export.cpp msgid "Landscape" -msgstr "" +msgstr "چشم‌انداز" #: platform/uwp/export/export.cpp msgid "Portrait" @@ -20826,7 +20827,7 @@ msgstr "" #: platform/windows/export/export.cpp msgid "Wine" -msgstr "" +msgstr "شراب" #: platform/x11/export/export.cpp msgid "32-bit executables cannot have embedded data >= 4 GiB." @@ -22586,7 +22587,7 @@ msgstr "" #: scene/3d/camera.cpp scene/3d/light.cpp scene/3d/reflection_probe.cpp msgid "Cull Mask" -msgstr "" +msgstr "Cull Mask" #: scene/3d/camera.cpp #, fuzzy @@ -26677,7 +26678,7 @@ msgstr "" #: scene/resources/environment.cpp msgid "Blur" -msgstr "" +msgstr "بلوری" #: scene/resources/environment.cpp msgid "Edge Sharpness" @@ -27530,9 +27531,8 @@ msgid "Depth Draw" msgstr "Øالت درون یابی(درون‌یابی روشی است برای یاÙتن مقدار تابع درون یک بازه)" #: scene/resources/visual_shader.cpp -#, fuzzy msgid "Cull" -msgstr "انتخاب Øالت" +msgstr "Cull" #: scene/resources/visual_shader.cpp #, fuzzy @@ -27735,9 +27735,8 @@ msgstr "Ø³Ø·Ø Ø¯Ø³ÛŒâ€ŒØ¨Ù„" #: servers/audio/effects/audio_effect_chorus.cpp #: servers/audio/effects/audio_effect_delay.cpp #: servers/audio/effects/audio_effect_panner.cpp -#, fuzzy msgid "Pan" -msgstr "بسته بندی" +msgstr "Pan" #: servers/audio/effects/audio_effect_compressor.cpp #: servers/audio/effects/audio_effect_filter.cpp diff --git a/editor/translations/fi.po b/editor/translations/fi.po index 8aeba71bff..96267c77e3 100644 --- a/editor/translations/fi.po +++ b/editor/translations/fi.po @@ -11269,7 +11269,7 @@ msgstr "Takaperspektiivi" msgid " [auto]" msgstr " [automaattinen]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portaalit aktiivisia]" diff --git a/editor/translations/fil.po b/editor/translations/fil.po index 71673d8255..2b6aa3a671 100644 --- a/editor/translations/fil.po +++ b/editor/translations/fil.po @@ -10674,7 +10674,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/fr.po b/editor/translations/fr.po index 17063caae8..f6b1b5d1c9 100644 --- a/editor/translations/fr.po +++ b/editor/translations/fr.po @@ -105,14 +105,17 @@ # SCHUTZ Lucas <lucas.schutz0954@gmail.com>, 2022. # EGuillemot <Elouen.Guillemot@gmail.com>, 2022. # Entiz <maxime.salido@gmail.com>, 2022. -# Callim Ethee <callimethee@gmail.com>, 2022. +# Callim Ethee <callimethee@gmail.com>, 2022, 2023. +# Hugo Berthet-Rambaud <hugoberthetrambaud@outlook.com>, 2023. +# Nathan Chambrette <n.chambrette@gmail.com>, 2023. +# slundi <slundi@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-10-10 18:06+0000\n" -"Last-Translator: Helix Sir <vincentbarkmann@gmail.com>\n" +"PO-Revision-Date: 2023-01-14 00:01+0000\n" +"Last-Translator: slundi <slundi@gmail.com>\n" "Language-Team: French <https://hosted.weblate.org/projects/godot-engine/" "godot/fr/>\n" "Language: fr\n" @@ -120,7 +123,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -325,7 +328,7 @@ msgstr "Pré-lecture de page" #: core/io/http_client.cpp msgid "Blocking Mode Enabled" -msgstr "Mode De Blocage Activé" +msgstr "Mode de blocage activé" #: core/io/http_client.cpp msgid "Connection" @@ -333,11 +336,11 @@ msgstr "Connexion" #: core/io/http_client.cpp msgid "Read Chunk Size" -msgstr "Taile des tronçons de lecture" +msgstr "Lire la taille des fragment(s)" #: core/io/marshalls.cpp msgid "Object ID" -msgstr "ID de l'Objet" +msgstr "Identifiant de l'Objet" #: core/io/multiplayer_api.cpp core/io/packet_peer.cpp msgid "Allow Object Decoding" @@ -596,7 +599,7 @@ msgstr "Message" #: core/os/input_event.cpp msgid "Pitch" -msgstr "Pitch" +msgstr "Angle d'attaque" #: core/os/input_event.cpp scene/2d/cpu_particles_2d.cpp #: scene/2d/physics_body_2d.cpp scene/3d/cpu_particles.cpp @@ -606,7 +609,7 @@ msgstr "Vélocité" #: core/os/input_event.cpp msgid "Instrument" -msgstr "Instrument" +msgstr "Appareil" #: core/os/input_event.cpp msgid "Controller Number" @@ -5904,7 +5907,6 @@ msgid "Zoom Modifier" msgstr "Touche de combinaison : Zoom" #: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Warped Mouse Panning" msgstr "Panoramique déformé de la souris" @@ -8843,15 +8845,15 @@ msgstr "Centré à Gauche" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Center Top" -msgstr "Centrée en Haut" +msgstr "Centré en Haut" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Center Right" -msgstr "Centrée à droite" +msgstr "Centré à droite" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Center Bottom" -msgstr "Centrée en bas" +msgstr "Centré en bas" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Center" @@ -11083,7 +11085,7 @@ msgstr "Perspective arrière" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portails actifs]" @@ -16833,7 +16835,7 @@ msgstr "Ajouter une entrée architecture" #: modules/gdnative/gdnative_library_editor_plugin.cpp msgid "GDNativeLibrary" -msgstr "GDNativeLibrary" +msgstr "Bibliothèque Native GD" #: modules/gdnative/gdnative_library_singleton_editor.cpp msgid "Enabled GDNative Singleton" @@ -17153,7 +17155,6 @@ msgid "Specular Factor" msgstr "Facteur Spéculaire" #: modules/gltf/gltf_spec_gloss.cpp -#, fuzzy msgid "Spec Gloss Img" msgstr "Img Spéculaire Brillante" @@ -18172,23 +18173,23 @@ msgstr "Module de %s" #: modules/visual_script/visual_script_func_nodes.cpp msgid "ShiftLeft %s" -msgstr "Décalage %s vers la gauche" +msgstr "Déplacer Vers la Gauche" #: modules/visual_script/visual_script_func_nodes.cpp msgid "ShiftRight %s" -msgstr "Décaler %s vers la droite" +msgstr "Déplacer vers la Droite" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitAnd %s" -msgstr "Et par bit %s" +msgstr "ET Binaire" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitOr %s" -msgstr "Ou par bit %s" +msgstr "OU Binaire" #: modules/visual_script/visual_script_func_nodes.cpp msgid "BitXor %s" -msgstr "Ou-exclusif par bit %s" +msgstr "OU Exclusif Binaire" #: modules/visual_script/visual_script_func_nodes.cpp msgid "Set Mode" @@ -18303,7 +18304,7 @@ msgstr "Récupérer Self" #: modules/visual_script/visual_script_nodes.cpp msgid "CustomNode" -msgstr "NÅ“ud Personnalisé" +msgstr "Noeud Personalisé" #: modules/visual_script/visual_script_nodes.cpp msgid "Custom node has no _step() method, can't process graph." @@ -18357,7 +18358,7 @@ msgstr "Yield" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Wait" -msgstr "Wait" +msgstr "Attente/Attendre" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Next Frame" @@ -19267,7 +19268,7 @@ msgstr "Projecteur 80 X 80" #: platform/iphone/export/export.cpp msgid "Storyboard" -msgstr "Storyboard" +msgstr "Story-board" #: platform/iphone/export/export.cpp msgid "Use Launch Screen Storyboard" @@ -20272,15 +20273,14 @@ msgid "Could not find wine executable at \"%s\"." msgstr "Impossible de trouver wine à l'emplacement \"%s\"." #: platform/windows/export/export.cpp -#, fuzzy msgid "" "Could not start rcedit executable. Configure rcedit path in the Editor " "Settings (Export > Windows > Rcedit), or disable \"Application > Modify " "Resources\" in the export preset." msgstr "" -"L'outil « rcedit » doit être configuré dans les préférences de l'éditeur " -"(Exporter > Windows > Rcedit) for modifier l'icône ou les informations de " -"l'application." +"Impossible de démarrer l'exécutable rcedit. Configurez le chemin vers rcedit " +"dans les réglages de l'éditeur (Exporter > Windows > Rcedit), ou désactivez " +"\"Application > Modifier les Ressources\" dans les préréglages de l'export." #: platform/windows/export/export.cpp msgid "rcedit failed to modify executable: %s." @@ -20303,15 +20303,14 @@ msgid "Invalid timestamp server." msgstr "Server d'horodatage invalide." #: platform/windows/export/export.cpp -#, fuzzy msgid "" "Could not start signtool executable. Configure signtool path in the Editor " "Settings (Export > Windows > Signtool), or disable \"Codesign\" in the " "export preset." msgstr "" -"L'outil « rcedit » doit être configuré dans les préférences de l'éditeur " -"(Exporter > Windows > Rcedit) for modifier l'icône ou les informations de " -"l'application." +"Impossible de démarrer l'exécutable signtool. Configurez le chemin vers " +"signtool dans les réglages de l'éditeur (Exporter > Windows > Signtool) ou " +"désactivez \"Codesign\" dans les préréglages de l'export." #: platform/windows/export/export.cpp msgid "Signtool failed to sign executable: %s." @@ -20567,14 +20566,12 @@ msgid "Draw Margin" msgstr "Afficher les marges" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Drag Margin H Enabled" -msgstr "Définir la marge" +msgstr "Marge de tirage H activée" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Drag Margin V Enabled" -msgstr "Définir la marge" +msgstr "Marge de tirage V activée" #: scene/2d/camera_2d.cpp msgid "Smoothing" @@ -20589,9 +20586,8 @@ msgid "V" msgstr "V" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Drag Margin" -msgstr "Tirer la marge" +msgstr "Marge Tirage" #: scene/2d/camera_2d.cpp msgid "Draw Screen" @@ -20602,9 +20598,8 @@ msgid "Draw Limits" msgstr "Afficher les limites" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Draw Drag Margin" -msgstr "Définir la marge" +msgstr "Dessiner la marge de tirage" #: scene/2d/canvas_item.cpp scene/resources/environment.cpp #: scene/resources/material.cpp @@ -21633,9 +21628,8 @@ msgid "Internal Vertex Count" msgstr "Nombre de Sommet Interne" #: scene/2d/position_2d.cpp -#, fuzzy msgid "Gizmo Extents" -msgstr "Gadgets" +msgstr "Etendues des Gadgets" #: scene/2d/ray_cast_2d.cpp scene/3d/ray_cast.cpp msgid "Exclude Parent" @@ -23258,9 +23252,8 @@ msgid "Gizmo" msgstr "Gizmo" #: scene/3d/spatial_velocity_tracker.cpp -#, fuzzy msgid "Track Physics Step" -msgstr "Image physique %" +msgstr "Suivre les Etapes Physiques" #: scene/3d/spring_arm.cpp msgid "Spring Length" @@ -23682,9 +23675,8 @@ msgid "Group" msgstr "Groupe" #: scene/gui/button.cpp scene/gui/label.cpp -#, fuzzy msgid "Clip Text" -msgstr "Copier le texte" +msgstr "Découper le texte" #: scene/gui/button.cpp scene/gui/label.cpp scene/gui/line_edit.cpp #: scene/gui/spin_box.cpp @@ -23696,9 +23688,8 @@ msgid "Icon Align" msgstr "Aligner l'icône" #: scene/gui/button.cpp -#, fuzzy msgid "Expand Icon" -msgstr "Développer tout" +msgstr "Développer l'icône" #: scene/gui/center_container.cpp msgid "Use Top Left" @@ -23795,9 +23786,8 @@ msgid "Pivot Offset" msgstr "Décalage du Pivot" #: scene/gui/control.cpp -#, fuzzy msgid "Clip Content" -msgstr "Constante de classe" +msgstr "Découper le contenu" #: scene/gui/control.cpp scene/resources/visual_shader_nodes.cpp msgid "Hint" @@ -23845,7 +23835,7 @@ msgstr "Forme de Curseur par Défaut" #: scene/gui/control.cpp msgid "Pass On Modal Close Click" -msgstr "" +msgstr "Transmettre Clic de Fermeture du Mode" #: scene/gui/control.cpp msgid "Size Flags" @@ -23856,9 +23846,8 @@ msgid "Stretch Ratio" msgstr "Ratio d’étirement" #: scene/gui/control.cpp -#, fuzzy msgid "Theme Type Variation" -msgstr "Propriétés du thème" +msgstr "Variation du Type du Thème" #: scene/gui/dialogs.cpp msgid "Window Title" @@ -23881,18 +23870,16 @@ msgid "Please Confirm..." msgstr "Veuillez confirmer…" #: scene/gui/file_dialog.cpp -#, fuzzy msgid "Mode Overrides Title" -msgstr "Remplacer l'item" +msgstr "Le Mode remplace le Titre" #: scene/gui/file_dialog.cpp msgid "Must use a valid extension." msgstr "Utilisez une extension valide." #: scene/gui/graph_edit.cpp -#, fuzzy msgid "Right Disconnects" -msgstr "Déconnecter" +msgstr "La droite déconnecte" #: scene/gui/graph_edit.cpp msgid "Scroll Offset" @@ -23928,9 +23915,8 @@ msgid "Enable grid minimap." msgstr "Activer l'alignement." #: scene/gui/graph_node.cpp -#, fuzzy msgid "Show Close" -msgstr "Afficher les os" +msgstr "Afficher la Fermeture" #: scene/gui/graph_node.cpp scene/gui/option_button.cpp #: scene/resources/default_theme/default_theme.cpp @@ -23959,23 +23945,20 @@ msgid "Incremental Search Max Interval Msec" msgstr "Intervalle max de recherche incrémentale (ms)" #: scene/gui/item_list.cpp scene/gui/tree.cpp -#, fuzzy msgid "Allow Reselect" -msgstr "Appliquer la réinitialisation" +msgstr "Autoriser la Resélection" #: scene/gui/item_list.cpp scene/gui/tree.cpp -#, fuzzy msgid "Allow RMB Select" -msgstr "Remplir la sélection" +msgstr "Autoriser la sélection par click droit" #: scene/gui/item_list.cpp msgid "Max Text Lines" msgstr "Lignes de texte max" #: scene/gui/item_list.cpp -#, fuzzy msgid "Auto Height" -msgstr "En période de test" +msgstr "Hauteur Auto" #: scene/gui/item_list.cpp msgid "Max Columns" @@ -23994,23 +23977,20 @@ msgid "Icon Scale" msgstr "Échelle de l'Icône" #: scene/gui/item_list.cpp -#, fuzzy msgid "Fixed Icon Size" -msgstr "Vue de devant" +msgstr "Taille d'Icône Fixe" #: scene/gui/label.cpp -#, fuzzy msgid "V Align" -msgstr "Assigner" +msgstr "Alignement V" #: scene/gui/label.cpp scene/gui/rich_text_label.cpp msgid "Visible Characters" msgstr "Caractères visibles" #: scene/gui/label.cpp scene/gui/rich_text_label.cpp -#, fuzzy msgid "Percent Visible" -msgstr "Rendre visible" +msgstr "Pourcentage visible" #: scene/gui/label.cpp msgid "Lines Skipped" @@ -24037,34 +24017,28 @@ msgid "Expand To Text Length" msgstr "Etendre à la longueur du texte" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp -#, fuzzy msgid "Context Menu Enabled" -msgstr "Aide contextuelle" +msgstr "Menu Contextuel Activé" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp -#, fuzzy msgid "Virtual Keyboard Enabled" -msgstr "Filtrer les signaux" +msgstr "Clavier Virtuel Activé" #: scene/gui/line_edit.cpp -#, fuzzy msgid "Clear Button Enabled" -msgstr "Filtrer les signaux" +msgstr "Bouton de Nettoyage Activé" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp -#, fuzzy msgid "Shortcut Keys Enabled" -msgstr "Raccourcis" +msgstr "Raccourcis activés" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp -#, fuzzy msgid "Middle Mouse Paste Enabled" -msgstr "Filtrer les signaux" +msgstr "Collage avec le bouton central de la souris activé" #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp -#, fuzzy msgid "Selecting Enabled" -msgstr "Sélection uniquement" +msgstr "Sélection Activée" #: scene/gui/line_edit.cpp scene/gui/rich_text_label.cpp #: scene/gui/text_edit.cpp @@ -24072,14 +24046,12 @@ msgid "Deselect On Focus Loss Enabled" msgstr "Déselection à la perte de focus activée" #: scene/gui/line_edit.cpp -#, fuzzy msgid "Right Icon" -msgstr "Bouton droit" +msgstr "Icône droite" #: scene/gui/line_edit.cpp -#, fuzzy msgid "Placeholder" -msgstr "Charger en tant qu'instance temporaire" +msgstr "Substitut temporaire" #: scene/gui/line_edit.cpp msgid "Alpha" @@ -24102,24 +24074,20 @@ msgid "Underline" msgstr "Souligner" #: scene/gui/menu_button.cpp -#, fuzzy msgid "Switch On Hover" -msgstr "Switch" +msgstr "Chnager au Survol" #: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp -#, fuzzy msgid "Draw Center" -msgstr "Centre" +msgstr "Dessiner le Centre" #: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp -#, fuzzy msgid "Region Rect" -msgstr "Définir région rectangulaire" +msgstr "Zone Rectangulaire" #: scene/gui/nine_patch_rect.cpp -#, fuzzy msgid "Patch Margin" -msgstr "Définir la marge" +msgstr "Marge de patch" #: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp msgid "Axis Stretch" @@ -24138,7 +24106,6 @@ msgstr "" "un étirement." #: scene/gui/popup.cpp -#, fuzzy msgid "Popup" msgstr "Fenêtre contextuelle" @@ -24170,9 +24137,8 @@ msgid "Hide On State Item Selection" msgstr "Cacher lors de la sélection de l'élément d'état" #: scene/gui/popup_menu.cpp -#, fuzzy msgid "Submenu Popup Delay" -msgstr "Délai du pop-up du sous-menu" +msgstr "Délai de pop-up du sous-menu" #: scene/gui/popup_menu.cpp msgid "Allow Search" @@ -24205,9 +24171,8 @@ msgid "Exp Edit" msgstr "Édition Exponentielle" #: scene/gui/range.cpp -#, fuzzy msgid "Rounded" -msgstr "Arrondir" +msgstr "Arrondi" #: scene/gui/range.cpp msgid "Allow Greater" @@ -24238,9 +24203,8 @@ msgid "Elapsed Time" msgstr "Temps Écoulé" #: scene/gui/rich_text_effect.cpp -#, fuzzy msgid "Env" -msgstr "Fin" +msgstr "Alentours" #: scene/gui/rich_text_effect.cpp msgid "Character" @@ -24298,18 +24262,16 @@ msgstr "" "définissez manuellement la taille minimale personnalisée." #: scene/gui/scroll_container.cpp -#, fuzzy msgid "Follow Focus" -msgstr "Remplir la surface" +msgstr "Suivre le focus" #: scene/gui/scroll_container.cpp msgid "Horizontal Enabled" msgstr "Horizontal Activé" #: scene/gui/scroll_container.cpp -#, fuzzy msgid "Vertical Enabled" -msgstr "Filtrer les signaux" +msgstr "Vertical Activé" #: scene/gui/scroll_container.cpp msgid "Default Scroll Deadzone" @@ -24320,9 +24282,8 @@ msgid "Scrollable" msgstr "Défilant" #: scene/gui/slider.cpp -#, fuzzy msgid "Tick Count" -msgstr "Prélever une couleur" +msgstr "Compte des Tics" #: scene/gui/slider.cpp msgid "Ticks On Borders" @@ -24341,14 +24302,12 @@ msgid "Split Offset" msgstr "Décalage des écarts" #: scene/gui/split_container.cpp scene/gui/tree.cpp -#, fuzzy msgid "Collapsed" -msgstr "Réduire tout" +msgstr "Réduit" #: scene/gui/split_container.cpp -#, fuzzy msgid "Dragger Visibility" -msgstr "Basculer la visibilité" +msgstr "Visibilité du Tireur" #: scene/gui/tab_container.cpp scene/gui/tabs.cpp msgid "Tab Align" @@ -24359,9 +24318,8 @@ msgid "Current Tab" msgstr "Onglet actuel" #: scene/gui/tab_container.cpp -#, fuzzy msgid "Tabs Visible" -msgstr "Rendre visible" +msgstr "Onglets Visibles" #: scene/gui/tab_container.cpp msgid "All Tabs In Front" @@ -24388,33 +24346,28 @@ msgid "Readonly" msgstr "Lecture Seule" #: scene/gui/text_edit.cpp -#, fuzzy msgid "Bookmark Gutter" -msgstr "Signets" +msgstr "Bandeau à Marque-pages" #: scene/gui/text_edit.cpp -#, fuzzy msgid "Breakpoint Gutter" -msgstr "Passer les points d'arrêt" +msgstr "Bandeau à points d'arrêt" #: scene/gui/text_edit.cpp msgid "Fold Gutter" msgstr "Replier le bandeau" #: scene/gui/text_edit.cpp -#, fuzzy msgid "Drag And Drop Selection Enabled" -msgstr "Sélection uniquement" +msgstr "Sélection en Glisser-déposer Activée" #: scene/gui/text_edit.cpp -#, fuzzy msgid "Hiding Enabled" -msgstr "Activer" +msgstr "Cacher Activé" #: scene/gui/text_edit.cpp -#, fuzzy msgid "Wrap Enabled" -msgstr "Activer" +msgstr "Déformation Activée" #: scene/gui/text_edit.cpp msgid "Scroll Vertical" @@ -24429,9 +24382,8 @@ msgid "Draw" msgstr "Dessiner" #: scene/gui/text_edit.cpp -#, fuzzy msgid "Block Mode" -msgstr "Déverrouiller le nÅ“ud" +msgstr "Mode Bloc" #: scene/gui/text_edit.cpp msgid "Moving By Right Click" @@ -24451,34 +24403,29 @@ msgid "Hover" msgstr "Survoler" #: scene/gui/texture_button.cpp -#, fuzzy msgid "Focused" -msgstr "Focaliser le chemin" +msgstr "Focalisé" #: scene/gui/texture_button.cpp -#, fuzzy msgid "Click Mask" -msgstr "Mode collision" +msgstr "Masque de Clic" #: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp #: scene/gui/video_player.cpp -#, fuzzy msgid "Expand" -msgstr "Développer tout" +msgstr "Développer" #: scene/gui/texture_progress.cpp msgid "Under" msgstr "Sous" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Over" -msgstr "Écraser" +msgstr "Par-dessus" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Progress" -msgstr "Propriétés du thème" +msgstr "Progrès" #: scene/gui/texture_progress.cpp msgid "Progress Offset" @@ -24497,43 +24444,36 @@ msgid "Radial Fill" msgstr "Remplissage Radial" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Initial Angle" -msgstr "Initialiser" +msgstr "Angle Initial" #: scene/gui/texture_progress.cpp msgid "Fill Degrees" msgstr "Degrés remplis" #: scene/gui/texture_progress.cpp scene/resources/primitive_meshes.cpp -#, fuzzy msgid "Center Offset" -msgstr "Centré à Gauche" +msgstr "Décalage du Centre" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Nine Patch Stretch" -msgstr "Mode d’interpolation" +msgstr "Etirement à Neuf Patchs" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Stretch Margin Left" -msgstr "Définir la marge" +msgstr "Etirer la marge à gauche" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Stretch Margin Top" -msgstr "Définir la marge" +msgstr "Etirer la marge en haut" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Stretch Margin Right" -msgstr "Définir la marge" +msgstr "Etirer la marge à droite" #: scene/gui/texture_progress.cpp -#, fuzzy msgid "Stretch Margin Bottom" -msgstr "Mode sélection" +msgstr "Etirer la marge en bas" #: scene/gui/tree.cpp msgid "Custom Minimum Height" @@ -24544,14 +24484,12 @@ msgid "(Other)" msgstr "(Autre)" #: scene/gui/tree.cpp -#, fuzzy msgid "Column Titles Visible" -msgstr "Rendre visible" +msgstr "Titres des colonnes visibles" #: scene/gui/tree.cpp -#, fuzzy msgid "Hide Folding" -msgstr "Bouton désactivé" +msgstr "Cacher les plis" #: scene/gui/tree.cpp msgid "Hide Root" @@ -24562,43 +24500,36 @@ msgid "Drop Mode Flags" msgstr "Options du Mode Abandon" #: scene/gui/video_player.cpp -#, fuzzy msgid "Audio Track" -msgstr "Ajouter une piste" +msgstr "Piste Audio" #: scene/gui/video_player.cpp scene/main/scene_tree.cpp scene/main/timer.cpp msgid "Paused" msgstr "En Pause" #: scene/gui/video_player.cpp -#, fuzzy msgid "Buffering Msec" -msgstr "Vue de derrière" +msgstr "Mise en mémoire tampon ms" #: scene/gui/video_player.cpp -#, fuzzy msgid "Stream Position" -msgstr "Définir position d'entrée de la courbe" +msgstr "Position Flux" #: scene/gui/viewport_container.cpp -#, fuzzy msgid "Stretch Shrink" -msgstr "Actualiser" +msgstr "Etirer-Réduire" #: scene/main/canvas_layer.cpp -#, fuzzy msgid "Follow Viewport" -msgstr "Afficher le Viewport" +msgstr "Suivre la fenêtre d'affichage" #: scene/main/http_request.cpp -#, fuzzy msgid "Download File" -msgstr "Télécharger" +msgstr "Télécharger le Fichier" #: scene/main/http_request.cpp -#, fuzzy msgid "Download Chunk Size" -msgstr "Téléchargement en cours" +msgstr "Taille des Blocs de Téléchargement" #: scene/main/http_request.cpp msgid "Body Size Limit" @@ -24621,80 +24552,68 @@ msgstr "" "'%s', car ce nom est déjà attribué à '%s'. Ce nÅ“ud n'est donc plus unique." #: scene/main/node.cpp -#, fuzzy msgid "Name Num Separator" -msgstr "Séparateur nommé" +msgstr "Nom des séparateurs numériques" #: scene/main/node.cpp msgid "Name Casing" msgstr "Convention de Nommage" #: scene/main/node.cpp -#, fuzzy msgid "Editor Description" -msgstr "Description" +msgstr "Description de l'Editeur" #: scene/main/node.cpp -#, fuzzy msgid "Pause Mode" -msgstr "Mode navigation" +msgstr "Mode Pause" #: scene/main/node.cpp -#, fuzzy msgid "Physics Interpolation Mode" -msgstr "Mode d’interpolation" +msgstr "Mode d’interpolation physique" #: scene/main/node.cpp -#, fuzzy msgid "Display Folded" -msgstr "Afficher sans ombrage" +msgstr "Afficher les repliés" #: scene/main/node.cpp -#, fuzzy msgid "Filename" -msgstr "Renommer" +msgstr "Nom de fichier" #: scene/main/node.cpp msgid "Owner" msgstr "Propriétaire" #: scene/main/node.cpp scene/main/scene_tree.cpp -#, fuzzy msgid "Multiplayer" -msgstr "Multiplier %s" +msgstr "Multijoueur" #: scene/main/node.cpp msgid "Custom Multiplayer" msgstr "Multijoueur Personnalisé" #: scene/main/node.cpp -#, fuzzy msgid "Process Priority" -msgstr "Activer la priorité" +msgstr "Priorité de processus" #: scene/main/scene_tree.cpp scene/main/timer.cpp -#, fuzzy msgid "Time Left" -msgstr "En haut à gauche" +msgstr "Temps restant" #: scene/main/scene_tree.cpp -#, fuzzy msgid "Debug Collisions Hint" -msgstr "Mode collision" +msgstr "Déboguer les indices de collision" #: scene/main/scene_tree.cpp -#, fuzzy msgid "Debug Navigation Hint" -msgstr "Mode Navigation" +msgstr "Déboguer les indices de navigation" #: scene/main/scene_tree.cpp msgid "Use Font Oversampling" msgstr "Utiliser le Suréchantillonnage de Police" #: scene/main/scene_tree.cpp -#, fuzzy msgid "Edited Scene Root" -msgstr "Nouvelle racine de scène" +msgstr "Racine de scène modifiée" #: scene/main/scene_tree.cpp msgid "Root" @@ -24778,9 +24697,8 @@ msgstr "" "Environnement -> Environnement par défaut) ne peut pas être chargé." #: scene/main/scene_tree.cpp -#, fuzzy msgid "Enable Object Picking" -msgstr "Activer l'effet « pelure d'oignon »" +msgstr "Activer la sélection d'objet" #: scene/main/timer.cpp msgid "" @@ -24829,14 +24747,12 @@ msgid "ARVR" msgstr "ARVR" #: scene/main/viewport.cpp -#, fuzzy msgid "Size Override Stretch" -msgstr "Remplacer l'item" +msgstr "La taille passe outre l'étirement" #: scene/main/viewport.cpp -#, fuzzy msgid "Own World" -msgstr "Propre Monde" +msgstr "Monde Propre" #: scene/main/viewport.cpp scene/resources/world_2d.cpp msgid "World" @@ -24859,9 +24775,8 @@ msgid "FXAA" msgstr "FXAA" #: scene/main/viewport.cpp -#, fuzzy msgid "Debanding" -msgstr "Liaison" +msgstr "Dé-banding" #: scene/main/viewport.cpp msgid "Disable 3D" @@ -24888,9 +24803,8 @@ msgid "V Flip" msgstr "Miroir V" #: scene/main/viewport.cpp -#, fuzzy msgid "Clear Mode" -msgstr "Mode Règle" +msgstr "Mode Nettoyage" #: scene/main/viewport.cpp msgid "Enable 2D" @@ -24901,18 +24815,16 @@ msgid "Enable 3D" msgstr "Activer 3D" #: scene/main/viewport.cpp -#, fuzzy msgid "Object Picking" -msgstr "Activer l'effet « pelure d'oignon »" +msgstr "Sélection d'objet" #: scene/main/viewport.cpp msgid "Disable Input" msgstr "Désactiver entrées" #: scene/main/viewport.cpp servers/visual_server.cpp -#, fuzzy msgid "Shadow Atlas" -msgstr "Nouvel Atlas" +msgstr "Atlas d'ombres" #: scene/main/viewport.cpp msgid "Quad 0" @@ -25000,9 +24912,8 @@ msgid "Segments" msgstr "Segments" #: scene/resources/curve.cpp -#, fuzzy msgid "Bake Resolution" -msgstr "Demi résolution" +msgstr "Précalculer la résolution" #: scene/resources/curve.cpp msgid "Bake Interval" @@ -25133,19 +25044,16 @@ msgid "Cursor Color" msgstr "Couleur du curseur" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Clear Button Color" -msgstr "Filtrer les signaux" +msgstr "Couleur du bouton de nettoyage" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Clear Button Color Pressed" -msgstr "Filtrer les signaux" +msgstr "Couleur du bouton de nettoyage appuyé" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Minimum Spaces" -msgstr "Scène principale" +msgstr "Espacement Minimum" #: scene/resources/default_theme/default_theme.cpp msgid "BG" @@ -25251,12 +25159,11 @@ msgstr "Signet" #: scene/resources/default_theme/default_theme.cpp msgid "Updown" -msgstr "" +msgstr "Haut/Bas" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Scaleborder Size" -msgstr "Pixels de bordure" +msgstr "Taille de la bordure du cadre" #: scene/resources/default_theme/default_theme.cpp msgid "Title Font" @@ -25307,9 +25214,8 @@ msgid "Font Separator" msgstr "Séparateur de police" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Font Color Accel" -msgstr "Renommer l'item de couleur" +msgstr "Accélération de la couleur de police" #: scene/resources/default_theme/default_theme.cpp msgid "Font Color Separator" @@ -25328,14 +25234,12 @@ msgid "Default Frame" msgstr "Trame par défaut" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Default Focus" -msgstr "Défaut" +msgstr "Focalisation par défaut" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Comment Focus" -msgstr "Enregistrer" +msgstr "Focalisation des commentaires" #: scene/resources/default_theme/default_theme.cpp msgid "Breakpoint" @@ -25366,14 +25270,12 @@ msgid "Port Offset" msgstr "Décalage du port" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "BG Focus" -msgstr "Focaliser le chemin" +msgstr "Focalisation de l'arrière-plan" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Selected Focus" -msgstr "Sélectionner" +msgstr "Focalisation de la sélection" #: scene/resources/default_theme/default_theme.cpp msgid "Cursor Unfocused" @@ -25384,19 +25286,16 @@ msgid "Button Pressed" msgstr "Bouton quand pressé" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Title Button Normal" -msgstr "Bouton à bascule (toggle)" +msgstr "Bouton de titre normal" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Title Button Pressed" -msgstr "Bouton à bascule (toggle)" +msgstr "Bouton de titre appuyé" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Title Button Hover" -msgstr "Bouton à bascule (toggle)" +msgstr "Bouton de titre survolé" #: scene/resources/default_theme/default_theme.cpp msgid "Custom Button" @@ -25411,33 +25310,28 @@ msgid "Custom Button Hover" msgstr "Bouton personnalisé au survol" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Select Arrow" -msgstr "Tout sélectionner" +msgstr "Flèche de sélection" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Arrow Collapsed" -msgstr "Réduire tout" +msgstr "Flèche réduite" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Title Button Font" -msgstr "Bouton à bascule (toggle)" +msgstr "Police du bouton de titre" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Title Button Color" -msgstr "Couleur de la Sélection" +msgstr "Couleur du bouton de titre" #: scene/resources/default_theme/default_theme.cpp msgid "Guide Color" msgstr "Couleur des guides" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Drop Position Color" -msgstr "Position du dock" +msgstr "Couleur de position du dépôt" #: scene/resources/default_theme/default_theme.cpp msgid "Relationship Line Color" @@ -25500,14 +25394,12 @@ msgid "Menu Highlight" msgstr "Menu au survol" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Font Color FG" -msgstr "Renommer l'item de couleur" +msgstr "Couleur de police premier plan" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Font Color BG" -msgstr "Renommer l'item de couleur" +msgstr "Couleur de police arrière-plan" #: scene/resources/default_theme/default_theme.cpp msgid "Side Margin" @@ -25519,11 +25411,11 @@ msgstr "Marge en haut" #: scene/resources/default_theme/default_theme.cpp msgid "Label V Align FG" -msgstr "" +msgstr "Alignement Vertical du Label Premier Plan" #: scene/resources/default_theme/default_theme.cpp msgid "Label V Align BG" -msgstr "" +msgstr "Alignement Vertical du Label Arrière-plan" #: scene/resources/default_theme/default_theme.cpp msgid "Large" @@ -25546,19 +25438,16 @@ msgid "Files Disabled" msgstr "Fichiers désactivés" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "SV Width" -msgstr "Étendu à Gauche" +msgstr "Largeur SV" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "SV Height" -msgstr "Lumière" +msgstr "Hauteur SV" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "H Width" -msgstr "Étendu à Gauche" +msgstr "Largeur H" #: scene/resources/default_theme/default_theme.cpp msgid "Label Width" @@ -25673,9 +25562,8 @@ msgid "Activity" msgstr "Activité" #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Bezier Len Pos" -msgstr "Déplacer des points de Bézier" +msgstr "Position de longueur de Bézier" #: scene/resources/default_theme/default_theme.cpp msgid "Bezier Len Neg" @@ -25842,9 +25730,8 @@ msgid "Max Luma" msgstr "Lumen maximum" #: scene/resources/environment.cpp -#, fuzzy msgid "SS Reflections" -msgstr "Mettre à l'échelle la sélection" +msgstr "Reflets SS" #: scene/resources/environment.cpp msgid "Max Steps" @@ -25879,14 +25766,12 @@ msgid "Intensity 2" msgstr "Intensité 2" #: scene/resources/environment.cpp scene/resources/material.cpp -#, fuzzy msgid "Light Affect" -msgstr "Étendu à Droite" +msgstr "Influence de la lumière" #: scene/resources/environment.cpp -#, fuzzy msgid "AO Channel Affect" -msgstr "Débogage du canal UV" +msgstr "Influence du canal AO" #: scene/resources/environment.cpp msgid "Blur" @@ -26158,12 +26043,11 @@ msgstr "NormalMap" #: scene/resources/material.cpp msgid "Rim" -msgstr "Bord" +msgstr "Bordure" #: scene/resources/material.cpp -#, fuzzy msgid "Clearcoat" -msgstr "Effacer" +msgstr "Coucheclaire" #: scene/resources/material.cpp msgid "Gloss" @@ -26175,7 +26059,7 @@ msgstr "Anisotropie" #: scene/resources/material.cpp msgid "Flowmap" -msgstr "" +msgstr "Organigramme" #: scene/resources/material.cpp msgid "Ambient Occlusion" @@ -26186,23 +26070,20 @@ msgid "Deep Parallax" msgstr "Parallaxe Profonde" #: scene/resources/material.cpp -#, fuzzy msgid "Min Layers" -msgstr "Calque" +msgstr "Calques min" #: scene/resources/material.cpp -#, fuzzy msgid "Max Layers" -msgstr "Calque" +msgstr "Calques max" #: scene/resources/material.cpp msgid "Flip Tangent" msgstr "Inverser la Tangente" #: scene/resources/material.cpp -#, fuzzy msgid "Flip Binormal" -msgstr "Retourner le Portal" +msgstr "Inversion Bi-normale" #: scene/resources/material.cpp msgid "Subsurf Scatter" @@ -26241,9 +26122,8 @@ msgid "UV2" msgstr "UV2" #: scene/resources/material.cpp -#, fuzzy msgid "Proximity Fade" -msgstr "Mode prioritaire" +msgstr "Fondu de proximité" #: scene/resources/material.cpp msgid "Distance Fade" @@ -26254,9 +26134,8 @@ msgid "Async Mode" msgstr "Mode asynchrone" #: scene/resources/mesh.cpp -#, fuzzy msgid "Lightmap Size Hint" -msgstr "LightMap Bake" +msgstr "Indice de taille de la texture de lumière" #: scene/resources/mesh.cpp scene/resources/primitive_meshes.cpp msgid "Custom AABB" @@ -26307,9 +26186,8 @@ msgid "Source Geometry Mode" msgstr "Mode Géométrie Source" #: scene/resources/navigation_mesh.cpp -#, fuzzy msgid "Source Group Name" -msgstr "Source" +msgstr "Nom du groupe source" #: scene/resources/navigation_mesh.cpp msgid "Cells" @@ -26332,18 +26210,16 @@ msgid "Regions" msgstr "Régions" #: scene/resources/navigation_mesh.cpp -#, fuzzy msgid "Merge Size" -msgstr "Fusionner depuis la scène" +msgstr "Taille de la fusion" #: scene/resources/navigation_mesh.cpp msgid "Edges" msgstr "Arêtes" #: scene/resources/navigation_mesh.cpp -#, fuzzy msgid "Max Error" -msgstr "Erreur" +msgstr "Erreur max" #: scene/resources/navigation_mesh.cpp msgid "Verts Per Poly" @@ -26358,9 +26234,8 @@ msgid "Sample Distance" msgstr "Échantillonner la distance" #: scene/resources/navigation_mesh.cpp -#, fuzzy msgid "Sample Max Error" -msgstr "Échantillonneur" +msgstr "Échantillon erreur max" #: scene/resources/navigation_mesh.cpp msgid "Low Hanging Obstacles" @@ -26375,14 +26250,12 @@ msgid "Walkable Low Height Spans" msgstr "Etendues de faible hauteur praticables" #: scene/resources/navigation_mesh.cpp -#, fuzzy msgid "Baking AABB" -msgstr "Générer AABB" +msgstr "Précalcul AABB" #: scene/resources/navigation_mesh.cpp -#, fuzzy msgid "Baking AABB Offset" -msgstr "Décalage :" +msgstr "Décalage du Précalcul AABB" #: scene/resources/occluder_shape.cpp msgid "Spheres" @@ -26413,14 +26286,12 @@ msgid "Divisor" msgstr "Diviseur" #: scene/resources/particles_material.cpp -#, fuzzy msgid "Size Modifier" -msgstr "Modificateur de vitesse de la vue libre" +msgstr "Modificateur de taille" #: scene/resources/particles_material.cpp -#, fuzzy msgid "Color Modifier" -msgstr "Ralentissement de la vue libre" +msgstr "Modificateur de couleur" #: scene/resources/particles_material.cpp msgid "Point Texture" @@ -26431,9 +26302,8 @@ msgid "Normal Texture" msgstr "Texture Normale" #: scene/resources/particles_material.cpp -#, fuzzy msgid "Color Texture" -msgstr "Thème de l'éditeur" +msgstr "Texture de couleur" #: scene/resources/particles_material.cpp msgid "Point Count" @@ -26444,9 +26314,8 @@ msgid "Scale Random" msgstr "Échelle Aléatoire" #: scene/resources/particles_material.cpp -#, fuzzy msgid "Scale Curve" -msgstr "Fermer la courbe" +msgstr "Courbe d'échelle" #: scene/resources/physics_material.cpp msgid "Rough" @@ -26485,9 +26354,8 @@ msgid "Top Radius" msgstr "Rayon Supérieur" #: scene/resources/primitive_meshes.cpp -#, fuzzy msgid "Bottom Radius" -msgstr "En bas à droite" +msgstr "Rayon bas" #: scene/resources/primitive_meshes.cpp msgid "Left To Right" @@ -26574,18 +26442,16 @@ msgid "Content Margin" msgstr "Marge de contenu" #: scene/resources/style_box.cpp -#, fuzzy msgid "Expand Margin" -msgstr "Développer tout" +msgstr "Développer la marge" #: scene/resources/style_box.cpp msgid "Skew" msgstr "Biseau" #: scene/resources/style_box.cpp -#, fuzzy msgid "Corner Radius" -msgstr "Changer le rayon intérieur de la tour" +msgstr "Rayon de coin" #: scene/resources/style_box.cpp msgid "Corner Detail" @@ -26604,9 +26470,8 @@ msgid "Grow End" msgstr "Fin d'Expansion" #: scene/resources/texture.cpp -#, fuzzy msgid "Load Path" -msgstr "Charger un préréglage" +msgstr "Charger chemin" #: scene/resources/texture.cpp msgid "Base Texture" @@ -26673,14 +26538,12 @@ msgid "Output Port For Preview" msgstr "Port de sortie de l'aperçu" #: scene/resources/visual_shader.cpp -#, fuzzy msgid "Depth Draw" -msgstr "Mode d’interpolation" +msgstr "Dessin en profondeur" #: scene/resources/visual_shader.cpp -#, fuzzy msgid "Cull" -msgstr "Mode Règle" +msgstr "élaguer/élagage" #: scene/resources/visual_shader.cpp msgid "Diffuse" @@ -26727,9 +26590,8 @@ msgid "Cube Map" msgstr "Textures en cube" #: scene/resources/visual_shader_nodes.cpp -#, fuzzy msgid "Default Value Enabled" -msgstr "Profil des fonctionnalités de Godot" +msgstr "Valeur par défaut activée" #: scene/resources/visual_shader_nodes.cpp msgid "Default Value" @@ -26757,25 +26619,23 @@ msgstr "Carte de navigation" #: scene/resources/world.cpp scene/resources/world_2d.cpp msgid "Direct Space State" -msgstr "" +msgstr "Etat de l'espace direct" #: scene/resources/world.cpp scene/resources/world_2d.cpp msgid "Default Gravity Vector" msgstr "Vecteur de gravité par défaut" #: scene/resources/world.cpp scene/resources/world_2d.cpp -#, fuzzy msgid "Default Linear Damp" -msgstr "Linéaire gauche" +msgstr "Amorti linéaire par défaut" #: scene/resources/world.cpp scene/resources/world_2d.cpp msgid "Default Angular Damp" -msgstr "" +msgstr "Amorti Angulaire par Défaut" #: scene/resources/world.cpp -#, fuzzy msgid "Default Map Up" -msgstr "Défaut" +msgstr "Haut de carte par défaut" #: scene/resources/world.cpp scene/resources/world_2d.cpp msgid "Default Cell Size" @@ -26807,7 +26667,7 @@ msgstr "AR" #: servers/arvr/arvr_interface.cpp msgid "Is Anchor Detection Enabled" -msgstr "" +msgstr "La détection d'ancre est-elle activée" #: servers/arvr_server.cpp msgid "Primary Interface" @@ -26869,7 +26729,7 @@ msgstr "Niveau (dB)" #: servers/audio/effects/audio_effect_delay.cpp #: servers/audio/effects/audio_effect_panner.cpp msgid "Pan" -msgstr "Pan" +msgstr "Panoramique/faire un panoramique" #: servers/audio/effects/audio_effect_compressor.cpp #: servers/audio/effects/audio_effect_filter.cpp @@ -26890,15 +26750,15 @@ msgstr "Mixer" #: servers/audio/effects/audio_effect_compressor.cpp msgid "Sidechain" -msgstr "" +msgstr "Sidechain" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 1" -msgstr "" +msgstr "Tap 1" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 2" -msgstr "" +msgstr "Tap 2" #: servers/audio/effects/audio_effect_delay.cpp #: servers/audio/effects/audio_effect_phaser.cpp @@ -26920,7 +26780,7 @@ msgstr "Garder haute fréquences (Hz)" #: servers/audio/effects/audio_effect_distortion.cpp msgid "Drive" -msgstr "" +msgstr "Elan" #: servers/audio/effects/audio_effect_distortion.cpp msgid "Post Gain" @@ -26940,11 +26800,11 @@ msgstr "Seuil de dB" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Soft Clip dB" -msgstr "" +msgstr "dB de Coupure Douce" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Soft Clip Ratio" -msgstr "" +msgstr "Ratio de Coupure Douce" #: servers/audio/effects/audio_effect_phaser.cpp msgid "Range Min Hz" @@ -26956,7 +26816,7 @@ msgstr "Borne supérieure de la plage (Hz)" #: servers/audio/effects/audio_effect_pitch_shift.cpp msgid "Oversampling" -msgstr "Suréchantillonnage" +msgstr "Sur-échantillonnage" #: servers/audio/effects/audio_effect_pitch_shift.cpp #: servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -26981,11 +26841,11 @@ msgstr "Passe-haut" #: servers/audio/effects/audio_effect_spectrum_analyzer.cpp msgid "Tap Back Pos" -msgstr "" +msgstr "Tap Position Arrière" #: servers/audio/effects/audio_effect_stereo_enhance.cpp msgid "Pan Pullout" -msgstr "" +msgstr "Retrait du Panoramique" #: servers/audio/effects/audio_effect_stereo_enhance.cpp msgid "Time Pullout (ms)" @@ -27008,9 +26868,8 @@ msgid "Channel Disable Threshold dB" msgstr "Désactiver le seuil de dB du canal" #: servers/audio_server.cpp -#, fuzzy msgid "Channel Disable Time" -msgstr "Changer le temps de mélange" +msgstr "Temps de désactivation de canal" #: servers/audio_server.cpp msgid "Video Delay Compensation (ms)" @@ -27054,7 +26913,7 @@ msgstr "Taille de la Table de Hachage BP" #: servers/physics_2d/physics_2d_server_sw.cpp msgid "Large Object Surface Threshold In Cells" -msgstr "" +msgstr "Seuil de Surface des Grands Objets dans les Cellules" #: servers/physics_2d_server.cpp servers/physics_server.cpp msgid "Inverse Mass" @@ -27113,14 +26972,12 @@ msgid "Collision Depth" msgstr "Profondeur de collision" #: servers/physics_2d_server.cpp servers/physics_server.cpp -#, fuzzy msgid "Collision Safe Fraction" -msgstr "Mode collision" +msgstr "Fraction anti-collisions" #: servers/physics_2d_server.cpp servers/physics_server.cpp -#, fuzzy msgid "Collision Unsafe Fraction" -msgstr "Mode collision" +msgstr "Fraction avec collisions potentielles" #: servers/physics_2d_server.cpp servers/physics_server.cpp msgid "Physics Engine" @@ -27139,22 +26996,20 @@ msgid "Varying may not be assigned in the '%s' function." msgstr "Varying ne peut pas être assigné dans la fonction '%s'." #: servers/visual/shader_language.cpp -#, fuzzy msgid "" "Varyings which were assigned in 'vertex' function may not be reassigned in " "'fragment' or 'light'." msgstr "" -"Les Varyings assignées dans la fonction \"vertex\" ne peuvent pas être " -"réassignées dans 'fragment' ou 'light'." +"Les variations assignées dans la fonction \"sommet/vertex\" ne peuvent pas " +"être réassignées dans \"fragment\" ou \"lumière/light\"." #: servers/visual/shader_language.cpp -#, fuzzy msgid "" "Varyings which were assigned in 'fragment' function may not be reassigned in " "'vertex' or 'light'." msgstr "" -"Les Varyings attribuées dans la fonction 'fragment' ne peuvent pas être " -"réattribuées dans 'vertex' ou 'light'." +"Les variations attribuées dans la fonction \"fragment\" ne peuvent pas être " +"réattribuées dans \"sommet/vertex\" ou \"lumière/light\"." #: servers/visual/shader_language.cpp msgid "Assignment to function." @@ -27173,9 +27028,8 @@ msgid "Spatial Partitioning" msgstr "Partitionnement Spatial" #: servers/visual_server.cpp -#, fuzzy msgid "Render Loop Enabled" -msgstr "Filtrer les signaux" +msgstr "Boucle de rendu activée" #: servers/visual_server.cpp msgid "VRAM Compression" @@ -27215,28 +27069,27 @@ msgstr "Niveau de compression WebP" #: servers/visual_server.cpp msgid "Time Rollover Secs" -msgstr "" +msgstr "Temps de Roulement en Secondes" #: servers/visual_server.cpp -#, fuzzy msgid "Cubemap Size" -msgstr "Changer la taille d'une caméra" +msgstr "Taille de la Cubemap" #: servers/visual_server.cpp msgid "Quadrant 0 Subdiv" -msgstr "" +msgstr "Subdivisions Quadrant 0" #: servers/visual_server.cpp msgid "Quadrant 1 Subdiv" -msgstr "" +msgstr "Subdivision Quadrant 1" #: servers/visual_server.cpp msgid "Quadrant 2 Subdiv" -msgstr "" +msgstr "Subdivision Quadrant 2" #: servers/visual_server.cpp msgid "Quadrant 3 Subdiv" -msgstr "" +msgstr "Subdivision Quadrant 3" #: servers/visual_server.cpp msgid "Shadows" @@ -27247,9 +27100,8 @@ msgid "Filter Mode" msgstr "Mode de filtrage" #: servers/visual_server.cpp -#, fuzzy msgid "Texture Array Reflections" -msgstr "Centrer sur la sélection" +msgstr "Refléxions de la liste de textures" #: servers/visual_server.cpp msgid "High Quality GGX" @@ -27257,7 +27109,7 @@ msgstr "GGX haute qualité" #: servers/visual_server.cpp msgid "Irradiance Max Size" -msgstr "" +msgstr "Taille Max Irradiance" #: servers/visual_server.cpp msgid "Shading" @@ -27265,7 +27117,7 @@ msgstr "Ombrage" #: servers/visual_server.cpp msgid "Force Vertex Shading" -msgstr "" +msgstr "Forcer l'Ombrage des Sommets" #: servers/visual_server.cpp msgid "Force Lambert Over Burley" @@ -27277,24 +27129,23 @@ msgstr "Forcer Blinn au lieu de GGX" #: servers/visual_server.cpp msgid "Mesh Storage" -msgstr "" +msgstr "Stockage de Maillage" #: servers/visual_server.cpp -#, fuzzy msgid "Split Stream" -msgstr "Scinder la courbe" +msgstr "Séparer flux" #: servers/visual_server.cpp msgid "Use Physical Light Attenuation" -msgstr "" +msgstr "Utiliser l'Atténuation Lumineuse Physique" #: servers/visual_server.cpp msgid "Depth Prepass" -msgstr "" +msgstr "Pré-passe de Profondeur" #: servers/visual_server.cpp msgid "Disable For Vendors" -msgstr "" +msgstr "Désactiver pour les Vendeurs" #: servers/visual_server.cpp msgid "Anisotropic Filter Level" @@ -27310,15 +27161,15 @@ msgstr "Enveloppement" #: servers/visual_server.cpp msgid "Software Skinning Fallback" -msgstr "" +msgstr "Dépouillement Logiciel de Repli" #: servers/visual_server.cpp msgid "Force Software Skinning" -msgstr "" +msgstr "Forcer le Dépouillement Logiciel" #: servers/visual_server.cpp msgid "Use Software Skinning" -msgstr "" +msgstr "Utiliser Dépouillement Logiciel" #: servers/visual_server.cpp msgid "Ninepatch Mode" @@ -27330,7 +27181,7 @@ msgstr "OpenGL" #: servers/visual_server.cpp msgid "Batching Send Null" -msgstr "" +msgstr "Traitement en Lot - Envoyer Null" #: servers/visual_server.cpp msgid "Batching Stream" @@ -27338,11 +27189,11 @@ msgstr "Flux de traitement en lot" #: servers/visual_server.cpp msgid "Legacy Orphan Buffers" -msgstr "" +msgstr "Anciens Tampons Orphelins" #: servers/visual_server.cpp msgid "Legacy Stream" -msgstr "" +msgstr "Ancien Flux" #: servers/visual_server.cpp msgid "Batching" @@ -27358,19 +27209,19 @@ msgstr "Utiliser le traitement en lot dans l'éditeur" #: servers/visual_server.cpp msgid "Single Rect Fallback" -msgstr "" +msgstr "Rectangle Unique de Repli" #: servers/visual_server.cpp msgid "Max Join Item Commands" -msgstr "" +msgstr "Commandes Max de Jointure d'Elements" #: servers/visual_server.cpp msgid "Colored Vertex Format Threshold" -msgstr "" +msgstr "Seuil de Format des Sommets Colorés" #: servers/visual_server.cpp msgid "Scissor Area Threshold" -msgstr "" +msgstr "Seuil d'Aire de Cisaillement" #: servers/visual_server.cpp msgid "Max Join Items" @@ -27386,7 +27237,7 @@ msgstr "Anticipation de réorganisation d’éléments" #: servers/visual_server.cpp msgid "Flash Batching" -msgstr "" +msgstr "Traitement en Lot Flash" #: servers/visual_server.cpp msgid "Diagnose Frame" @@ -27405,9 +27256,8 @@ msgid "Disable Half Float" msgstr "Désactiver les demi Float" #: servers/visual_server.cpp -#, fuzzy msgid "Enable High Float" -msgstr "Activer la priorité" +msgstr "Activer les grands flottants" #: servers/visual_server.cpp msgid "Precision" @@ -27434,19 +27284,16 @@ msgid "Use Signals" msgstr "Utiliser les signaux" #: servers/visual_server.cpp -#, fuzzy msgid "Remove Danglers" -msgstr "Supprimer la tuile" +msgstr "Supprimer les pendouillants" #: servers/visual_server.cpp -#, fuzzy msgid "Flip Imported Portals" -msgstr "Retourner les Portals" +msgstr "Retourner les portails importés" #: servers/visual_server.cpp -#, fuzzy msgid "Occlusion Culling" -msgstr "Voir la suppression de l'occlusion" +msgstr "Elagage de l'occlusion" #: servers/visual_server.cpp msgid "Max Active Spheres" diff --git a/editor/translations/ga.po b/editor/translations/ga.po index 01810bb059..eea95f8656 100644 --- a/editor/translations/ga.po +++ b/editor/translations/ga.po @@ -10649,7 +10649,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/gl.po b/editor/translations/gl.po index 1d2fbb333a..9bfb2b9309 100644 --- a/editor/translations/gl.po +++ b/editor/translations/gl.po @@ -11231,7 +11231,7 @@ msgstr "Perspetiva" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/he.po b/editor/translations/he.po index 57b2386570..7458eedd15 100644 --- a/editor/translations/he.po +++ b/editor/translations/he.po @@ -26,13 +26,14 @@ # Tomer Ben Rachel <tomerpacific@gmail.com>, 2022. # moshe mil <milgmoshe@gmail.com>, 2022. # Blawnode <blawnode@gmail.com>, 2022. +# Yoni m <yoni.meirov08@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-23 20:47+0000\n" -"Last-Translator: Blawnode <blawnode@gmail.com>\n" +"PO-Revision-Date: 2023-01-01 05:48+0000\n" +"Last-Translator: Yoni m <yoni.meirov08@gmail.com>\n" "Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/" "godot/he/>\n" "Language: he\n" @@ -41,7 +42,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && " "n % 10 == 0) ? 2 : 3));\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -274,9 +275,8 @@ msgid "Network Peer" msgstr "מ×פיין\\עמית רשת" #: core/io/multiplayer_api.cpp scene/animation/animation_player.cpp -#, fuzzy msgid "Root Node" -msgstr "×©×™× ×•×™ ×©× ×ž×¤×¨×§ השורש" +msgstr "מפרק השורש" #: core/io/networked_multiplayer_peer.cpp msgid "Refuse New Connections" @@ -300,11 +300,11 @@ msgstr "פלוט גודל מירבי של החוצץ" #: core/io/packet_peer.cpp msgid "Stream Peer" -msgstr "" +msgstr "×–×¨× ×¢×ž×™×ª×™×" #: core/io/stream_peer.cpp msgid "Big Endian" -msgstr "" +msgstr "×× ×“×™×ן גדול" #: core/io/stream_peer.cpp #, fuzzy @@ -395,18 +395,16 @@ msgid "Device" msgstr "מכשיר" #: core/os/input_event.cpp -#, fuzzy msgid "Alt" -msgstr "הכל" +msgstr "×לט" #: core/os/input_event.cpp msgid "Shift" msgstr "הסט" #: core/os/input_event.cpp -#, fuzzy msgid "Control" -msgstr "בקרת גירס×ות" +msgstr "לשלוט" #: core/os/input_event.cpp msgid "Meta" @@ -417,9 +415,8 @@ msgid "Command" msgstr "פקודה" #: core/os/input_event.cpp -#, fuzzy msgid "Physical" -msgstr "פיזיקה" +msgstr "פיזי" #: core/os/input_event.cpp scene/2d/touch_screen_button.cpp #: scene/gui/base_button.cpp scene/gui/texture_button.cpp @@ -428,9 +425,8 @@ msgid "Pressed" msgstr "לחוץ" #: core/os/input_event.cpp -#, fuzzy msgid "Scancode" -msgstr "סריקת מקורות" +msgstr "קוד סריקה" #: core/os/input_event.cpp msgid "Physical Scancode" @@ -442,26 +438,23 @@ msgstr "×™×•× ×™×§×•×“" #: core/os/input_event.cpp msgid "Echo" -msgstr "" +msgstr "הד" #: core/os/input_event.cpp scene/gui/base_button.cpp -#, fuzzy msgid "Button Mask" -msgstr "כפתור" +msgstr "מסכת כפתור" #: core/os/input_event.cpp scene/2d/node_2d.cpp scene/gui/control.cpp -#, fuzzy msgid "Global Position" -msgstr "קבוע" +msgstr "×ž×™×§×•× ×’×œ×•×‘×œ×™" #: core/os/input_event.cpp msgid "Factor" msgstr "פקטור" #: core/os/input_event.cpp -#, fuzzy msgid "Button Index" -msgstr "מפתח כפתורי עכבר:" +msgstr "××™× ×“×§×¡ הכפתורי×" #: core/os/input_event.cpp msgid "Doubleclick" @@ -477,12 +470,11 @@ msgstr "לחץ" #: core/os/input_event.cpp msgid "Pen Inverted" -msgstr "" +msgstr "עט הפוך" #: core/os/input_event.cpp -#, fuzzy msgid "Relative" -msgstr "GDNative" +msgstr "קרוב משפחה" #: core/os/input_event.cpp scene/2d/camera_2d.cpp scene/2d/cpu_particles_2d.cpp #: scene/3d/cpu_particles.cpp scene/3d/interpolated_camera.cpp @@ -497,9 +489,8 @@ msgid "Axis" msgstr "ציר" #: core/os/input_event.cpp -#, fuzzy msgid "Axis Value" -msgstr "(ערך)" +msgstr "ערך ציר" #: core/os/input_event.cpp modules/visual_script/visual_script_func_nodes.cpp msgid "Index" @@ -529,16 +520,14 @@ msgid "Message" msgstr "מסר" #: core/os/input_event.cpp -#, fuzzy msgid "Pitch" -msgstr "גובה צליל" +msgstr "גובה הצליל" #: core/os/input_event.cpp scene/2d/cpu_particles_2d.cpp #: scene/2d/physics_body_2d.cpp scene/3d/cpu_particles.cpp #: scene/3d/physics_body.cpp scene/resources/particles_material.cpp -#, fuzzy msgid "Velocity" -msgstr "הגדלת ×ות ר××©×•× ×”" +msgstr "מְהִירוּת" #: core/os/input_event.cpp msgid "Instrument" @@ -559,14 +548,12 @@ msgid "Application" msgstr "×פליקציה" #: core/project_settings.cpp main/main.cpp -#, fuzzy msgid "Config" -msgstr "הגדרת הצמדה" +msgstr "×”×§×•× ×¤×“×¨×¦×™×”" #: core/project_settings.cpp -#, fuzzy msgid "Project Settings Override" -msgstr "הגדרות מיז×..." +msgstr "עקיפת הגדרות פרוייקט" #: core/project_settings.cpp core/resource.cpp #: editor/animation_track_editor.cpp editor/editor_autoload_settings.cpp @@ -597,7 +584,7 @@ msgstr "הרצה" #: core/project_settings.cpp editor/editor_node.cpp #: editor/run_settings_dialog.cpp main/main.cpp msgid "Main Scene" -msgstr "" +msgstr "×¡×¦× ×” ר×שית" #: core/project_settings.cpp msgid "Disable stdout" @@ -609,22 +596,21 @@ msgstr "השבת stderr" #: core/project_settings.cpp msgid "Use Hidden Project Data Directory" -msgstr "" +msgstr "שימוש בספריית × ×ª×•× ×™ פרוייקט מוסתרי×" #: core/project_settings.cpp msgid "Use Custom User Dir" -msgstr "" +msgstr "השתמש ב- Dir משתמש מות×× ×ישית" #: core/project_settings.cpp msgid "Custom User Dir Name" -msgstr "" +msgstr "×©× ×ª×™×§×™×™×ª משתמש מות×× ×ישית" #: core/project_settings.cpp main/main.cpp #: platform/javascript/export/export.cpp platform/osx/export/export.cpp #: platform/uwp/os_uwp.cpp -#, fuzzy msgid "Display" -msgstr "הצג הכל" +msgstr "הצג" #: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp #: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp @@ -643,7 +629,7 @@ msgstr "גבה" #: core/project_settings.cpp msgid "Always On Top" -msgstr "" +msgstr "תמיד עליון" #: core/project_settings.cpp msgid "Test Width" @@ -672,30 +658,27 @@ msgstr "עורך" #: core/project_settings.cpp msgid "Main Run Args" -msgstr "" +msgstr "×¤×¨×ž×˜×¨×™× ×¨××©×™×™× ×œ×¨×™×¦×”" #: core/project_settings.cpp -#, fuzzy msgid "Scene Naming" -msgstr "× ×ª×™×‘ ×¡×¦× ×•×ª:" +msgstr "מתן שמות ×œ×¡×¦×™× ×”" #: core/project_settings.cpp msgid "Search In File Extensions" -msgstr "" +msgstr "חיפוש בסיומות קבצי×" #: core/project_settings.cpp msgid "Script Templates Search Path" -msgstr "" +msgstr "× ×ª×™×‘ חיפוש של ×ª×‘× ×™×•×ª סקריפט" #: core/project_settings.cpp -#, fuzzy msgid "Version Control Autoload On Startup" -msgstr "בקרת גירס×ות" +msgstr "×˜×¢×™× ×” ×וטומטית של בקרת גירס×ות בעת ×”×תחול" #: core/project_settings.cpp -#, fuzzy msgid "Version Control Plugin Name" -msgstr "בקרת גירס×ות" +msgstr "×©× ×ª×•×¡×£ בקרת גרס×ות" #: core/project_settings.cpp scene/2d/collision_object_2d.cpp #: scene/3d/collision_object.cpp scene/gui/control.cpp @@ -704,62 +687,55 @@ msgstr "קלט" #: core/project_settings.cpp msgid "UI Accept" -msgstr "" +msgstr "ממשק משתמש - ×ישור" #: core/project_settings.cpp -#, fuzzy msgid "UI Select" -msgstr "בחירה" +msgstr "בחירת ממשק משתמש" #: core/project_settings.cpp msgid "UI Cancel" -msgstr "" +msgstr "ביטול ממשק משתמש" #: core/project_settings.cpp -#, fuzzy msgid "UI Focus Next" -msgstr "מיקוד × ×ª×™×‘" +msgstr "מיקוד ממשק המשתמש הב×" #: core/project_settings.cpp -#, fuzzy msgid "UI Focus Prev" -msgstr "מיקוד × ×ª×™×‘" +msgstr "מיקוד ממשק משתמש קוד×" #: core/project_settings.cpp -#, fuzzy msgid "UI Left" -msgstr "שמ×ל" +msgstr "ממשק משתמש שמ×ל" #: core/project_settings.cpp -#, fuzzy msgid "UI Right" -msgstr "ימין" +msgstr "ממשק משתמש ימין" #: core/project_settings.cpp msgid "UI Up" -msgstr "" +msgstr "ממשק משתמש למעלה" #: core/project_settings.cpp -#, fuzzy msgid "UI Down" -msgstr "הורדה" +msgstr "ממשק משתמש למטה" #: core/project_settings.cpp msgid "UI Page Up" -msgstr "" +msgstr "עמוד למעלה ממשק המשתמש" #: core/project_settings.cpp msgid "UI Page Down" -msgstr "" +msgstr "עמוד למטה ממשק משתמש" #: core/project_settings.cpp msgid "UI Home" -msgstr "" +msgstr "ממשק משתמש בית" #: core/project_settings.cpp -#, fuzzy msgid "UI End" -msgstr "בסוף" +msgstr "ממשק משתמש סוף" #: core/project_settings.cpp main/main.cpp modules/bullet/register_types.cpp #: modules/bullet/space_bullet.cpp scene/2d/physics_body_2d.cpp @@ -796,7 +772,7 @@ msgstr "" #: scene/main/viewport.cpp servers/visual/visual_server_scene.cpp #: servers/visual_server.cpp msgid "Rendering" -msgstr "" +msgstr "×¨×™× ×“×•×¨" #: core/project_settings.cpp drivers/gles2/rasterizer_storage_gles2.cpp #: drivers/gles3/rasterizer_scene_gles3.cpp @@ -816,7 +792,7 @@ msgstr "×ž×¡× × ×™×" #: core/project_settings.cpp scene/main/viewport.cpp msgid "Sharpen Intensity" -msgstr "" +msgstr "עוצמת חידוד" #: core/project_settings.cpp editor/editor_export.cpp editor/editor_node.cpp #: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp @@ -842,42 +818,40 @@ msgid "Profiler" msgstr "מ×פיין" #: core/project_settings.cpp -#, fuzzy msgid "Max Functions" -msgstr "יצירת ×¤×•× ×§×¦×™×”" +msgstr "×¤×•× ×§×¦×™×•×ª מקסימו×" #: core/project_settings.cpp scene/3d/vehicle_body.cpp msgid "Compression" msgstr "כיווץ" #: core/project_settings.cpp -#, fuzzy msgid "Formats" -msgstr "×ª×‘× ×™×ª" +msgstr "פורמטי×" #: core/project_settings.cpp msgid "Zstd" -msgstr "" +msgstr "Zstd" #: core/project_settings.cpp msgid "Long Distance Matching" -msgstr "" +msgstr "הת×מה ×œ×ž×¨×—×§×™× ×רוכי×" #: core/project_settings.cpp msgid "Compression Level" -msgstr "" +msgstr "רמת דחיסה" #: core/project_settings.cpp msgid "Window Log Size" -msgstr "" +msgstr "גודל חלון יומן" #: core/project_settings.cpp msgid "Zlib" -msgstr "" +msgstr "ZLIB" #: core/project_settings.cpp msgid "Gzip" -msgstr "" +msgstr "Gzip" #: core/project_settings.cpp platform/android/export/export.cpp msgid "Android" @@ -885,24 +859,23 @@ msgstr "Android" #: core/project_settings.cpp msgid "Modules" -msgstr "" +msgstr "מודולי×" #: core/register_core_types.cpp msgid "TCP" msgstr "TCP" #: core/register_core_types.cpp -#, fuzzy msgid "Connect Timeout Seconds" -msgstr "×©× ×™×•×ª קצובות להתחברות" +msgstr "זמן קצוב לחיבור ×‘×©× ×™×•×ª" #: core/register_core_types.cpp msgid "Packet Peer Stream" -msgstr "" +msgstr "×–×¨× ×¢×ž×™×ª ×ž× ×•×ª" #: core/register_core_types.cpp msgid "Max Buffer (Power of 2)" -msgstr "" +msgstr "גודל ×ž×—×¡× ×™×ª מקסימלי (בחזקה)" #: core/register_core_types.cpp editor/editor_settings.cpp main/main.cpp msgid "SSL" @@ -943,7 +916,7 @@ msgstr "בדיקה" #: core/translation.cpp scene/resources/font.cpp msgid "Fallback" -msgstr "" +msgstr "חזרה" #: core/ustring.cpp scene/resources/segment_shape_2d.cpp msgid "B" @@ -979,7 +952,7 @@ msgstr "EiB" #: drivers/gles3/rasterizer_scene_gles3.cpp #: drivers/gles3/rasterizer_storage_gles3.cpp modules/gltf/gltf_state.cpp msgid "Buffers" -msgstr "" +msgstr "×ž×—×¡× ×™×•×ª" #: drivers/gles2/rasterizer_canvas_base_gles2.cpp #: drivers/gles3/rasterizer_canvas_base_gles3.cpp @@ -1005,39 +978,36 @@ msgstr "2D" #: drivers/gles2/rasterizer_canvas_base_gles2.cpp #: drivers/gles3/rasterizer_canvas_base_gles3.cpp -#, fuzzy msgid "Snapping" -msgstr "הגדרות הצמדה" +msgstr "הצמדה" #: drivers/gles2/rasterizer_canvas_base_gles2.cpp #: drivers/gles3/rasterizer_canvas_base_gles3.cpp -#, fuzzy msgid "Use GPU Pixel Snap" -msgstr "מצב מרחב מקומי (%s)" +msgstr "שימוש בהצמדת ×¤×™×§×¡×œ×™× ×©×œ GPU" #: drivers/gles2/rasterizer_scene_gles2.cpp #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Immediate Buffer Size (KB)" -msgstr "" +msgstr "גודל ×ž×—×¡× ×™×ª מיידי (KB)" #: drivers/gles2/rasterizer_storage_gles2.cpp #: drivers/gles3/rasterizer_storage_gles3.cpp -#, fuzzy msgid "Lightmapping" -msgstr "×פיית Lightmaps" +msgstr "מיפוי ×ורות" #: drivers/gles2/rasterizer_storage_gles2.cpp #: drivers/gles3/rasterizer_storage_gles3.cpp msgid "Use Bicubic Sampling" -msgstr "" +msgstr "השתמש בדגימה דו-×›×™×•×•× ×™×ª" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Elements" -msgstr "" +msgstr "×ž×§×¡×™×ž×•× ×¨×›×™×‘×™× ×”× ×™×ª× ×™× ×œ×¨×™× ×“×•×¨" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Lights" -msgstr "" +msgstr "×ž×§×¡×™×ž×•× ×ורות × ×™×ª× ×™× ×œ×¨×™× ×“×•×¨" #: drivers/gles3/rasterizer_scene_gles3.cpp #, fuzzy @@ -1046,11 +1016,11 @@ msgstr "GridMap מחיקת הבחירה" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Lights Per Object" -msgstr "" +msgstr "×ž×§×¡×™×ž×•× ×ורות לכל ×ובייקט" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Subsurface Scattering" -msgstr "" +msgstr "פיזור תת-שטח" #: drivers/gles3/rasterizer_scene_gles3.cpp editor/animation_track_editor.cpp #: editor/import/resource_importer_texture.cpp @@ -1067,15 +1037,15 @@ msgstr "×§× ×” מידה" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Follow Surface" -msgstr "" +msgstr "עקוב ×חר ×¤× ×™ השטח" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Weight Samples" -msgstr "" +msgstr "דוגמ×ות משקל" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Voxel Cone Tracing" -msgstr "" +msgstr "מעקב חרוט ווקסל" #: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp msgid "High Quality" @@ -1192,7 +1162,7 @@ msgstr "כמות:" #: editor/animation_track_editor.cpp main/main.cpp #: modules/mono/mono_gd/gd_mono.cpp msgid "Args" -msgstr "" +msgstr "××¨×’×•×ž× ×˜×™×" #: editor/animation_track_editor.cpp editor/editor_settings.cpp #: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp @@ -1214,7 +1184,7 @@ msgstr "" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp msgid "Stream" -msgstr "" +msgstr "זר×" #: editor/animation_track_editor.cpp #, fuzzy @@ -1238,7 +1208,7 @@ msgstr "×”× ×¤×©×”" #: editor/animation_track_editor.cpp msgid "Easing" -msgstr "" +msgstr "הקלה (×× ×™×ž×¦×™×”)" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Keyframe Time" @@ -1373,7 +1343,7 @@ msgstr "×§× ×” מידה:" #: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Type:" -msgstr "" +msgstr "סוג:" #: editor/animation_track_editor.cpp #, fuzzy @@ -1466,7 +1436,7 @@ msgstr "שכפול מפתח(ות)" #: editor/animation_track_editor.cpp msgid "Add RESET Value(s)" -msgstr "" +msgstr "הוסף ערכי ×יפוס" #: editor/animation_track_editor.cpp msgid "Delete Key(s)" @@ -2232,7 +2202,7 @@ msgstr "פתיחה" #: editor/dependency_editor.cpp msgid "Owners of: %s (Total: %d)" -msgstr "" +msgstr "×‘×¢×œ×™× ×©×œ: %s (סה\"×›: %d)" #: editor/dependency_editor.cpp msgid "" @@ -2645,7 +2615,7 @@ msgstr "×©× ×©×’×•×™." #: editor/editor_autoload_settings.cpp msgid "Cannot begin with a digit." -msgstr "" +msgstr "×œ× × ×™×ª×Ÿ להתחיל ×¢× ×¡×™×¤×¨×”." #: editor/editor_autoload_settings.cpp msgid "Valid characters:" @@ -2790,7 +2760,7 @@ msgstr "בחירה" #: editor/editor_export.cpp msgid "Project export for platform:" -msgstr "" +msgstr "×™×™×¦×•× ×¤×¨×•×™×§×˜ לפלטפורמה:" #: editor/editor_export.cpp #, fuzzy @@ -2908,7 +2878,7 @@ msgstr "חברי×" #: platform/javascript/export/export.cpp platform/osx/export/export.cpp #: platform/uwp/export/export.cpp msgid "Release" -msgstr "" +msgstr "שחרר" #: editor/editor_export.cpp #, fuzzy @@ -2917,7 +2887,7 @@ msgstr "התמרה" #: editor/editor_export.cpp msgid "64 Bits" -msgstr "" +msgstr "64 ביטי×" #: editor/editor_export.cpp msgid "Embed PCK" @@ -2930,23 +2900,23 @@ msgstr "מצב ×©×™× ×•×™ ×§× ×” מידה (R)" #: editor/editor_export.cpp msgid "BPTC" -msgstr "" +msgstr "BPTC" #: editor/editor_export.cpp platform/osx/export/export.cpp msgid "S3TC" -msgstr "" +msgstr "S3TC" #: editor/editor_export.cpp platform/osx/export/export.cpp msgid "ETC" -msgstr "" +msgstr "ETC" #: editor/editor_export.cpp platform/osx/export/export.cpp msgid "ETC2" -msgstr "" +msgstr "ETC2" #: editor/editor_export.cpp msgid "No BPTC Fallbacks" -msgstr "" +msgstr "×ין חזרות BPTC" #: editor/editor_export.cpp platform/android/export/export_plugin.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -2991,7 +2961,7 @@ msgstr "×‘×™×™×¦×•× ×רכיטקטורת 32 ביט, ×” PCK ×”×ž×•×‘× ×” ×œ× ×™ #: editor/editor_export.cpp msgid "Convert Text Resources To Binary On Export" -msgstr "" +msgstr "המרת מש×בי טקסט ×œ×‘×™× ××¨×™×™× ×‘×™×™×¦×•×" #: editor/editor_feature_profile.cpp msgid "3D Editor" @@ -3315,7 +3285,7 @@ msgstr "הצג/הסתר ×§×‘×¦×™× ×ž×•×¡×ª×¨×™×" #: editor/editor_file_dialog.cpp msgid "Disable Overwrite Warning" -msgstr "" +msgstr "השבת ×ת ×זהרת החלפה" #: editor/editor_file_dialog.cpp msgid "Go Back" @@ -3471,16 +3441,16 @@ msgstr "קבועי×" #: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp msgid "Fonts" -msgstr "" +msgstr "×’×•×¤× ×™×" #: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp #: platform/iphone/export/export.cpp msgid "Icons" -msgstr "" +msgstr "סמלי×" #: editor/editor_help.cpp msgid "Styles" -msgstr "" +msgstr "×¡×’× ×•× ×•×ª" #: editor/editor_help.cpp msgid "Enumerations" @@ -3530,7 +3500,7 @@ msgstr "עזרה" #: editor/editor_help.cpp msgid "Sort Functions Alphabetically" -msgstr "" +msgstr "מיון ×¤×•× ×§×¦×™×•×ª בסדר ×לפביתי" #: editor/editor_help_search.cpp editor/editor_node.cpp #: editor/plugins/script_editor_plugin.cpp @@ -3622,7 +3592,7 @@ msgstr "מתודות בלבד" #: editor/editor_inspector.cpp editor/plugins/item_list_editor_plugin.cpp msgid "Checkable" -msgstr "" +msgstr "× ×™×ª×Ÿ לבדיקה" #: editor/editor_inspector.cpp editor/plugins/item_list_editor_plugin.cpp #: scene/resources/default_theme/default_theme.cpp @@ -3648,11 +3618,11 @@ msgstr "(ערך)" #: editor/editor_inspector.cpp msgid "" "Pinning a value forces it to be saved even if it's equal to the default." -msgstr "" +msgstr "הצמדת ערך מ×לצת ×ותו להישמר ×’× ×× ×”×•× ×©×•×•×” לברירת המחדל." #: editor/editor_inspector.cpp msgid "Pin value [Disabled because '%s' is editor-only]" -msgstr "" +msgstr "הצמדת ערך [מושבת מכיוון ש- '%s' ×”×•× ×œ-עורך בלבד]" #: editor/editor_inspector.cpp #: editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -3669,11 +3639,11 @@ msgstr "קביעה מרובה:" #: editor/editor_inspector.cpp msgid "Pinned %s" -msgstr "" +msgstr "הוצמד %s" #: editor/editor_inspector.cpp msgid "Unpinned %s" -msgstr "" +msgstr "בוטלה ההצמדה של %s" #: editor/editor_inspector.cpp #, fuzzy @@ -3761,7 +3731,7 @@ msgstr "חלון חדש" #: editor/editor_node.cpp editor/project_manager.cpp msgid "Unnamed Project" -msgstr "" +msgstr "פרויקט ×œ×œ× ×©×" #: editor/editor_node.cpp msgid "" @@ -3769,6 +3739,9 @@ msgid "" "Update Continuously is enabled, which can increase power usage. Click to " "disable it." msgstr "" +"מסתובב ×›×שר חלון העורך מצייר מחדש.\n" +"×”×פשרות 'עדכן רציף' מופעלת, מה שעלול להגביר ×ת צריכת החשמל. לחץ כדי להשבית " +"×ותו." #: editor/editor_node.cpp msgid "Spins when the editor window redraws." @@ -3895,6 +3868,8 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" +"×ירעה שגי××” בעת × ×™×¡×™×•×Ÿ לשמור ×ת פריסת העורך.\n" +"×•×“× ×©× ×ª×™×‘ × ×ª×•× ×™ המשתמש של העורך × ×™×ª×Ÿ לכתיבה." #: editor/editor_node.cpp msgid "" @@ -3902,6 +3877,9 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" +"פריסת עורך ברירת המחדל × ×“×¨×¡×ª.\n" +"כדי לשחזר ×ת פריסת ברירת המחדל להגדרות הבסיס שלה, השתמש ב×פשרות מחק פריסה " +"ומחק ×ת פריסת ברירת המחדל." #: editor/editor_node.cpp msgid "Layout name not found!" @@ -3963,7 +3941,7 @@ msgstr "×ין ×¡×¦× ×” מוגדרת להרצה." #: editor/editor_node.cpp msgid "Save scene before running..." -msgstr "" +msgstr "שמור ×¡×¦× ×” ×œ×¤× ×™ ריצה..." #: editor/editor_node.cpp msgid "Could not start subprocess!" @@ -4009,13 +3987,14 @@ msgstr "לשמור ×ת ×”×©×™× ×•×™×™× ×œÖ¾'%s' ×œ×¤× ×™ הסגירה?" #: editor/editor_node.cpp msgid "%s no longer exists! Please specify a new save location." -msgstr "" +msgstr "%s כבר ×œ× ×§×™×™×! × × ×œ×¦×™×™×Ÿ ×ž×™×§×•× ×©×ž×™×¨×” חדש." #: editor/editor_node.cpp msgid "" "The current scene has no root node, but %d modified external resource(s) " "were saved anyway." msgstr "" +"×œ×¡×¦× ×” ×”× ×•×›×—×™×ª ×ין צומת שורש, ×ך %d מש××‘×™× ×—×™×¦×•× ×™×™× ×©×©×•× ×• × ×©×ž×¨×• בכל מקרה." #: editor/editor_node.cpp #, fuzzy @@ -11258,7 +11237,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/hi.po b/editor/translations/hi.po index 657ee0ff41..229a1e6ee7 100644 --- a/editor/translations/hi.po +++ b/editor/translations/hi.po @@ -11065,7 +11065,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/hr.po b/editor/translations/hr.po index 85fcb184f3..d3ea72cf63 100644 --- a/editor/translations/hr.po +++ b/editor/translations/hr.po @@ -8,12 +8,13 @@ # LeoClose <leoclose575@gmail.com>, 2020, 2021, 2022. # Filip <fhomolka@protonmail.com>, 2022. # Milo Ivir <mail@milotype.de>, 2022. +# peter277 <ps2718@hotmail.com>, 2022. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" -"PO-Revision-Date: 2022-09-27 21:37+0000\n" -"Last-Translator: Milo Ivir <mail@milotype.de>\n" +"PO-Revision-Date: 2022-12-21 07:02+0000\n" +"Last-Translator: peter277 <ps2718@hotmail.com>\n" "Language-Team: Croatian <https://hosted.weblate.org/projects/godot-engine/" "godot/hr/>\n" "Language: hr\n" @@ -21,7 +22,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -3432,7 +3433,7 @@ msgstr "" #: editor/editor_help.cpp msgid "Enumerations" -msgstr "" +msgstr "Nabrajanja" #: editor/editor_help.cpp msgid "Property Descriptions" @@ -10824,7 +10825,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/hu.po b/editor/translations/hu.po index b8bab10568..ad7ba523e3 100644 --- a/editor/translations/hu.po +++ b/editor/translations/hu.po @@ -11273,7 +11273,7 @@ msgstr "PerspektÃva" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/id.po b/editor/translations/id.po index 89153d88d3..47b026986a 100644 --- a/editor/translations/id.po +++ b/editor/translations/id.po @@ -41,13 +41,14 @@ # Primananda Kurnia <primakurnia71@gmail.com>, 2022. # FellowMustard <rachmawanng33@gmail.com>, 2022. # Muhammad Zainal Abidin <eviepk12@gmail.com>, 2022. +# adfriz <aditiyaafrizal2@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-09-27 21:37+0000\n" -"Last-Translator: Muhammad Zainal Abidin <eviepk12@gmail.com>\n" +"PO-Revision-Date: 2023-01-04 10:47+0000\n" +"Last-Translator: adfriz <aditiyaafrizal2@gmail.com>\n" "Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/" "godot/id/>\n" "Language: id\n" @@ -55,7 +56,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -11181,7 +11182,7 @@ msgstr "Perspektif Belakang" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portal aktif]" @@ -20765,9 +20766,8 @@ msgid "Executable \"pck\" section not found." msgstr "" #: platform/windows/export/export.cpp -#, fuzzy msgid "Windows" -msgstr "Jendela Baru" +msgstr "Windows" #: platform/windows/export/export.cpp msgid "Rcedit" diff --git a/editor/translations/ig.po b/editor/translations/ig.po index e0c1a85c99..9acd1e98b7 100644 --- a/editor/translations/ig.po +++ b/editor/translations/ig.po @@ -10569,7 +10569,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/is.po b/editor/translations/is.po index 7551598f22..fda8086f4b 100644 --- a/editor/translations/is.po +++ b/editor/translations/is.po @@ -10792,7 +10792,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/it.po b/editor/translations/it.po index f1ff871a69..6010f082aa 100644 --- a/editor/translations/it.po +++ b/editor/translations/it.po @@ -73,7 +73,7 @@ # ale piccia <picciatialessio2@gmail.com>, 2022. # Simone Starace <simone.starace93@gmail.com>, 2022. # Daniele Giunta <danielegiunta2007@gmail.com>, 2022. -# Damiano Guida <damiano.guida22@gmail.com>, 2022. +# Damiano Guida <damiano.guida22@gmail.com>, 2022, 2023. # Silvia Scaglione <sissisoad@gmail.com>, 2022. # Cosimo Davide Viggiano <cosimod089@gmail.com>, 2022. # Francesco Cammarata <francescocammarata.fr@gmail.com>, 2022. @@ -82,8 +82,8 @@ msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-22 20:37+0000\n" -"Last-Translator: Francesco Cammarata <francescocammarata.fr@gmail.com>\n" +"PO-Revision-Date: 2023-01-15 13:34+0000\n" +"Last-Translator: Damiano Guida <damiano.guida22@gmail.com>\n" "Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/" "godot/it/>\n" "Language: it\n" @@ -91,7 +91,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -11031,7 +11031,7 @@ msgstr "Prospettica da dietro" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portali attivi]" @@ -26477,7 +26477,7 @@ msgstr "Debug del Canale UV" #: scene/resources/environment.cpp msgid "Blur" -msgstr "" +msgstr "Sfocatura" #: scene/resources/environment.cpp msgid "Edge Sharpness" diff --git a/editor/translations/ja.po b/editor/translations/ja.po index dc17329ba7..e7016610d7 100644 --- a/editor/translations/ja.po +++ b/editor/translations/ja.po @@ -46,13 +46,13 @@ # Fire Dingo <snowsable113@icloud.com>, 2022. # Narazaki Shuji <shujinarazaki@protonmail.com>, 2022. # ta ko <neji.cion@gmail.com>, 2022. -# T K <kidaaam@gmail.com>, 2022. +# T K <kidaaam@gmail.com>, 2022, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-12-13 13:21+0000\n" +"PO-Revision-Date: 2023-01-20 10:19+0000\n" "Last-Translator: T K <kidaaam@gmail.com>\n" "Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/" "godot/ja/>\n" @@ -61,7 +61,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -886,7 +886,6 @@ msgid "Connect Timeout Seconds" msgstr "接続タイムアウトã®ç§’æ•°" #: core/register_core_types.cpp -#, fuzzy msgid "Packet Peer Stream" msgstr "パケットピアストリーム" @@ -5288,12 +5287,11 @@ msgstr "ダイアãƒã‚°ã®ãƒãƒƒãƒ—アップ時ã«ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã‚’è–„æš—ãã™ #: editor/editor_settings.cpp main/main.cpp msgid "Low Processor Mode Sleep (µsec)" -msgstr "低プãƒã‚»ãƒƒã‚µ モード スリープ (マイクãƒç§’)" +msgstr "çœã‚¨ãƒãƒ¢ãƒ¼ãƒ‰ã‚¹ãƒªãƒ¼ãƒ—時間 (マイクãƒç§’)" #: editor/editor_settings.cpp -#, fuzzy msgid "Unfocused Low Processor Mode Sleep (µsec)" -msgstr "フォーカスã•ã‚Œã¦ã„ãªã„低プãƒã‚»ãƒƒã‚µ モード スリープ (マイクãƒç§’)" +msgstr "éžãƒ•ã‚©ãƒ¼ã‚«ã‚¹æ™‚ã®çœã‚¨ãƒãƒ¢ãƒ¼ãƒ‰ã‚¹ãƒªãƒ¼ãƒ—時間 (マイクãƒç§’)" #: editor/editor_settings.cpp msgid "Separate Distraction Mode" @@ -5346,9 +5344,8 @@ msgid "Border Size" msgstr "ボーダーサイズ" #: editor/editor_settings.cpp -#, fuzzy msgid "Use Graph Node Headers" -msgstr "グラフ ノード ヘッダーを使用ã™ã‚‹" +msgstr "グラフノードヘッダーを使用ã™ã‚‹" #: editor/editor_settings.cpp msgid "Additional Spacing" @@ -5690,9 +5687,8 @@ msgid "Secondary Grid Color" msgstr "グリッドã®ã‚»ã‚«ãƒ³ãƒ€ãƒªã®è‰²" #: editor/editor_settings.cpp -#, fuzzy msgid "Selection Box Color" -msgstr "é¸æŠžç¯„囲ã®ã¿" +msgstr "é¸æŠžãƒœãƒƒã‚¯ã‚¹ã®è‰²" #: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp @@ -5795,19 +5791,16 @@ msgid "Emulate 3 Button Mouse" msgstr "3ボタンマウスをエミュレート" #: editor/editor_settings.cpp -#, fuzzy msgid "Orbit Modifier" -msgstr "更新日時ãŒå¤ã„é †ã§ä¸¦ã³æ›¿ãˆ" +msgstr "オービットæ“作ã®ä¿®é£¾ã‚ー" #: editor/editor_settings.cpp -#, fuzzy msgid "Pan Modifier" -msgstr "パンモード" +msgstr "パンæ“作ã®ä¿®é£¾ã‚ー" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Modifier" -msgstr "変更済ã¿" +msgstr "ズームæ“作ã®ä¿®é£¾ã‚ー" #: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp #, fuzzy @@ -5815,38 +5808,32 @@ msgid "Warped Mouse Panning" msgstr "ワープマウスパンニング" #: editor/editor_settings.cpp -#, fuzzy msgid "Navigation Feel" -msgstr "ナビゲーションモード" +msgstr "ナビゲーション感度" #: editor/editor_settings.cpp -#, fuzzy msgid "Orbit Sensitivity" -msgstr "軌é“感度" +msgstr "オービット感度" #: editor/editor_settings.cpp -#, fuzzy msgid "Orbit Inertia" -msgstr "軌é“慣性" +msgstr "オービット慣性" #: editor/editor_settings.cpp -#, fuzzy msgid "Translation Inertia" -msgstr "翻訳" +msgstr "移動ã®æ…£æ€§" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Inertia" -msgstr "ズームイン" +msgstr "ズームã®æ…£æ€§" #: editor/editor_settings.cpp msgid "Freelook" msgstr "フリールック" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Navigation Scheme" -msgstr "ナビゲーションメッシュを生æˆ" +msgstr "フリールックナビゲーション方å¼" #: editor/editor_settings.cpp msgid "Freelook Sensitivity" @@ -5861,14 +5848,12 @@ msgid "Freelook Base Speed" msgstr "フリールックã®åŸºæœ¬é€Ÿåº¦" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Activation Modifier" -msgstr "フリールックã®æ¸›é€Ÿèª¿æ•´" +msgstr "フリールック有効化ã®ä¿®é£¾ã‚ー" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Speed Zoom Link" -msgstr "フリールックã®é€Ÿåº¦èª¿æ•´" +msgstr "フリールックã®é€Ÿåº¦ã‚’ズーム値ã«ãƒªãƒ³ã‚¯" #: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp msgid "Grid Color" @@ -5915,14 +5900,12 @@ msgid "Viewport Border Color" msgstr "ビューãƒãƒ¼ãƒˆã®ãƒœãƒ¼ãƒ€ãƒ¼ã®è‰²" #: editor/editor_settings.cpp -#, fuzzy msgid "Constrain Editor View" -msgstr "エディター ビューを制é™" +msgstr "エディタビューをæŸç¸›ã™ã‚‹" #: editor/editor_settings.cpp -#, fuzzy msgid "Simple Panning" -msgstr "簡易パンニング" +msgstr "簡易パンニングæ“作" #: editor/editor_settings.cpp #, fuzzy @@ -5930,23 +5913,20 @@ msgid "Scroll To Pan" msgstr "スクãƒãƒ¼ãƒ«ã—ã¦ãƒ‘ンニング" #: editor/editor_settings.cpp -#, fuzzy msgid "Pan Speed" -msgstr "速度:" +msgstr "パン速度" #: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp msgid "Poly Editor" msgstr "ãƒãƒªã‚´ãƒ³ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼" #: editor/editor_settings.cpp -#, fuzzy msgid "Point Grab Radius" -msgstr "ãƒã‚¤ãƒ³ãƒˆã‚°ãƒ©ãƒ–åŠå¾„" +msgstr "ãƒã‚¤ãƒ³ãƒˆã®é¸æŠžåŠå¾„" #: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Show Previous Outline" -msgstr "å‰ã®å¹³é¢" +msgstr "å‰ã®ã‚¢ã‚¦ãƒˆãƒ©ã‚¤ãƒ³ã‚’表示ã™ã‚‹" #: editor/editor_settings.cpp editor/scene_tree_dock.cpp msgid "Autorename Animation Tracks" @@ -5961,19 +5941,16 @@ msgid "Default Create Reset Tracks" msgstr "デフォルトã§RESETトラックを作æˆ" #: editor/editor_settings.cpp -#, fuzzy msgid "Onion Layers Past Color" msgstr "オニオンレイヤーéŽåŽ»ã®è‰²" #: editor/editor_settings.cpp -#, fuzzy msgid "Onion Layers Future Color" msgstr "オニオンレイヤー将æ¥ã®è‰²" #: editor/editor_settings.cpp -#, fuzzy msgid "Visual Editors" -msgstr "グループエディター" +msgstr "ビジュアルエディター" #: editor/editor_settings.cpp msgid "Minimap Opacity" @@ -6086,29 +6063,24 @@ msgid "Background Color" msgstr "背景色" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Background Color" -msgstr "無効ãªèƒŒæ™¯è‰²ã§ã™ã€‚" +msgstr "補完ã®èƒŒæ™¯è‰²" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Selected Color" -msgstr "é¸æŠžã•ã‚ŒãŸã‚‚ã®ã‚’インãƒãƒ¼ãƒˆ" +msgstr "補完ã®é¸æŠžä¸ã®è‰²" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Existing Color" -msgstr "æ—¢å˜ã®è‰²ã®è£œå®Œ" +msgstr "æ—¢ã«è£œå®Œã•ã‚Œã¦ã„る箇所ã®è‰²" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Scroll Color" -msgstr "スクãƒãƒ¼ãƒ«è‰²ã®è£œå®Œ" +msgstr "補完ウインドウã®ã‚¹ã‚¯ãƒãƒ¼ãƒ«è‰²" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Font Color" -msgstr "フォント色ã®è£œå®Œ" +msgstr "補完ã®ãƒ•ã‚©ãƒ³ãƒˆè‰²" #: editor/editor_settings.cpp msgid "Text Color" @@ -6135,9 +6107,8 @@ msgid "Text Selected Color" msgstr "é¸æŠžã•ã‚ŒãŸãƒ†ã‚ストã®è‰²" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Selection Color" -msgstr "é¸æŠžç¯„囲ã®ã¿" +msgstr "é¸æŠžè‰²" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Brace Mismatch Color" @@ -7235,14 +7206,12 @@ msgid "Fix Alpha Border" msgstr "アルファボーダーを修æ£" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Premult Alpha" -msgstr "ãƒãƒªã‚´ãƒ³ã‚’編集" +msgstr "乗算済ã¿ã‚¢ãƒ«ãƒ•ã‚¡" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Hdr As Srgb" -msgstr "Srgbã¨ã—ã¦Hdr" +msgstr "HDRã‚’sRGBã¨ã—ã¦è¡¨ç¤º" #: editor/import/resource_importer_texture.cpp msgid "Invert Color" @@ -10980,7 +10949,7 @@ msgstr "å¾Œé¢ é€è¦–投影" msgid " [auto]" msgstr " [自動]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [ãƒãƒ¼ã‚¿ãƒ«æœ‰åŠ¹]" @@ -14136,6 +14105,8 @@ msgid "" "Note: Encryption key needs to be stored in the binary,\n" "you need to build the export templates from source." msgstr "" +"注:æš—å·åŒ–ã‚ーã¯ãƒã‚¤ãƒŠãƒªã«æ ¼ç´ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n" +"ソースã‹ã‚‰ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ†ãƒ³ãƒ—レートをビルドã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚" #: editor/project_export.cpp msgid "More Info..." @@ -14242,17 +14213,15 @@ msgid "Invalid project path (changed anything?)." msgstr "無効ãªãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆãƒ‘スã§ã™ (ãªã«ã‹å¤‰æ›´ãŒã‚ã‚Šã¾ã—ãŸã‹ï¼Ÿ)。" #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." msgstr "" -"プãƒã‚¸ã‚§ã‚¯ãƒˆãƒ‘ス㮠project.godot ã‚’èªã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚ (エラー %d)。見ã¤ã‹" -"らãªã„ã‹ç ´æã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚" +"%s ã®ãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆã‚’èªã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚ (エラー %d)。見ã¤ã‹ã‚‰ãªã„ã‹ç ´æã—ã¦" +"ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚" #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "次ã®å ´æ‰€ã®ãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆã‚’é–‹ã‘ã¾ã›ã‚“ '%s'。" +msgstr "プãƒã‚¸ã‚§ã‚¯ãƒˆã‚’ '%s' ã«ä¿å˜ã§ãã¾ã›ã‚“ã§ã—㟠(エラー %d)。" #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -15510,6 +15479,9 @@ msgid "" "with the '%s' prefix in a node path.\n" "Click to disable this." msgstr "" +"ã“ã®ãƒŽãƒ¼ãƒ‰ã«ã¯ã€ãƒŽãƒ¼ãƒ‰ パスã®å…ˆé ã« '%s' プレフィックスを付ã‘ã‚‹ã“ã¨ã§ã€ã‚·ãƒ¼ãƒ³" +"内ã®ã©ã“ã‹ã‚‰ã§ã‚‚アクセスã§ãã¾ã™ã€‚\n" +"クリックã™ã‚‹ã¨ç„¡åŠ¹ã«ãªã‚Šã¾ã™ã€‚" #: editor/scene_tree_editor.cpp msgid "" @@ -15911,7 +15883,7 @@ msgstr "å…‰æºã®åŠå¾„を変更" #: editor/spatial_editor_gizmos.cpp msgid "Stream Player 3D" -msgstr "" +msgstr "ストリームプレイヤー3D" #: editor/spatial_editor_gizmos.cpp msgid "Change AudioStreamPlayer3D Emission Angle" @@ -15933,7 +15905,7 @@ msgstr "カメラサイズを変更" #: editor/spatial_editor_gizmos.cpp msgid "Visibility Notifier" -msgstr "" +msgstr "å¯è¦–性通知" #: editor/spatial_editor_gizmos.cpp msgid "Change Notifier AABB" @@ -15941,7 +15913,7 @@ msgstr "Notifierã®AABBを変更" #: editor/spatial_editor_gizmos.cpp msgid "Change Particles AABB" -msgstr "パーティクルã®è»¸å¹³è¡Œå¢ƒç•Œãƒœãƒƒã‚¯ã‚¹ã‚’変更" +msgstr "パーティクルã®AABBを変更" #: editor/spatial_editor_gizmos.cpp msgid "Reflection Probe" @@ -16113,9 +16085,8 @@ msgid "RID Pool Prealloc" msgstr "RIDプールã®äº‹å‰å‰²ã‚Šå½“ã¦" #: main/main.cpp -#, fuzzy msgid "Debugger stdout" -msgstr "デãƒãƒƒã‚¬ãƒ¼" +msgstr "デãƒãƒƒã‚¬ãƒ¼ã®æ¨™æº–出力" #: main/main.cpp msgid "Max Chars Per Second" @@ -16155,7 +16126,7 @@ msgstr "ãƒã‚°ã®ãƒ‘ス" #: main/main.cpp msgid "Max Log Files" -msgstr "" +msgstr "最大ãƒã‚°ãƒ•ã‚¡ã‚¤ãƒ«æ•°" #: main/main.cpp msgid "Driver" @@ -16195,7 +16166,7 @@ msgstr "ピクセルå˜ä½ã®é€æ˜Žåº¦" #: main/main.cpp msgid "Allowed" -msgstr "" +msgstr "許å¯" #: main/main.cpp msgid "Intended Usage" @@ -16206,9 +16177,8 @@ msgid "Framebuffer Allocation" msgstr "フレームãƒãƒƒãƒ•ã‚¡ã®å‰²ã‚Šå½“ã¦" #: main/main.cpp platform/uwp/os_uwp.cpp -#, fuzzy msgid "Energy Saving" -msgstr "ä¿å˜ä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ" +msgstr "çœã‚¨ãƒãƒ«ã‚®ãƒ¼" #: main/main.cpp msgid "Threads" @@ -16224,32 +16194,29 @@ msgstr "スレッドセーフãªBVH" #: main/main.cpp msgid "Handheld" -msgstr "" +msgstr "ãƒãƒ¼ã‚¿ãƒ–ル" #: main/main.cpp platform/javascript/export/export.cpp #: platform/uwp/export/export.cpp -#, fuzzy msgid "Orientation" -msgstr "オンラインドã‚ュメント" +msgstr "æ–¹å‘" #: main/main.cpp scene/gui/scroll_container.cpp scene/gui/text_edit.cpp #: scene/main/scene_tree.cpp scene/register_scene_types.cpp -#, fuzzy msgid "Common" -msgstr "コミュニティ" +msgstr "一般" #: main/main.cpp msgid "Physics FPS" msgstr "物ç†FPS" #: main/main.cpp -#, fuzzy msgid "Force FPS" -msgstr "強制プッシュ" +msgstr "強制FPS" #: main/main.cpp msgid "Enable Pause Aware Picking" -msgstr "" +msgstr "一時åœæ¢ä¸ã®é¸æŠžèªè˜ã®æœ‰åŠ¹åŒ–" #: main/main.cpp scene/gui/item_list.cpp scene/gui/popup_menu.cpp #: scene/gui/scroll_container.cpp scene/gui/text_edit.cpp scene/gui/tree.cpp @@ -16287,11 +16254,11 @@ msgstr "フレームé…延 (ミリ秒)" #: main/main.cpp msgid "Low Processor Mode" -msgstr "" +msgstr "低プãƒã‚»ãƒƒã‚µãƒ¢ãƒ¼ãƒ‰" #: main/main.cpp msgid "Delta Sync After Draw" -msgstr "" +msgstr "æ画後ã®ãƒ‡ãƒ«ã‚¿åŒæœŸ" #: main/main.cpp msgid "iOS" @@ -16299,7 +16266,7 @@ msgstr "iOS" #: main/main.cpp msgid "Hide Home Indicator" -msgstr "" +msgstr "ãƒ›ãƒ¼ãƒ ã‚¤ãƒ³ã‚¸ã‚±ãƒ¼ã‚¿ãƒ¼ã‚’éš ã™" #: main/main.cpp msgid "Input Devices" @@ -16322,9 +16289,8 @@ msgid "Shaders" msgstr "シェーダー" #: main/main.cpp -#, fuzzy msgid "Debug Shader Fallbacks" -msgstr "シェーダーフォールãƒãƒƒã‚¯ã‚’強制" +msgstr "シェーダーフォールãƒãƒƒã‚¯ã®ãƒ‡ãƒãƒƒã‚°" #: main/main.cpp scene/3d/baked_lightmap.cpp scene/3d/camera.cpp #: scene/3d/world_environment.cpp scene/main/scene_tree.cpp @@ -16334,16 +16300,15 @@ msgstr "環境" #: main/main.cpp msgid "Default Clear Color" -msgstr "" +msgstr "デフォルトã®ã‚¯ãƒªã‚¢ãƒ¼è‰²" #: main/main.cpp msgid "Boot Splash" msgstr "ブートスプラッシュ" #: main/main.cpp -#, fuzzy msgid "Show Image" -msgstr "ボーンを表示ã™ã‚‹" +msgstr "ç”»åƒã‚’表示" #: main/main.cpp msgid "Image" @@ -16375,7 +16340,7 @@ msgstr "ãƒãƒƒãƒ•ã‚¡ãƒªãƒ³ã‚°" #: main/main.cpp msgid "Agile Event Flushing" -msgstr "" +msgstr "å³åº§ã«ã‚¤ãƒ™ãƒ³ãƒˆãƒ•ãƒ©ãƒƒã‚·ãƒ¥" #: main/main.cpp msgid "Emulate Touch From Mouse" @@ -16390,13 +16355,12 @@ msgid "Mouse Cursor" msgstr "マウスカーソル" #: main/main.cpp -#, fuzzy msgid "Custom Image" -msgstr "ノードを切りå–ã‚‹" +msgstr "カスタムイメージ" #: main/main.cpp msgid "Custom Image Hotspot" -msgstr "" +msgstr "カスタムイメージホットスãƒãƒƒãƒˆ" #: main/main.cpp msgid "Tooltip Position Offset" @@ -16441,12 +16405,11 @@ msgstr "縮å°" #: main/main.cpp scene/main/scene_tree.cpp msgid "Auto Accept Quit" -msgstr "" +msgstr "プãƒã‚°ãƒ©ãƒ 終了を自動的ã«å—ã‘入れる" #: main/main.cpp scene/main/scene_tree.cpp -#, fuzzy msgid "Quit On Go Back" -msgstr "戻る" +msgstr "「戻るã€æ™‚ã«ãƒ—ãƒã‚°ãƒ©ãƒ 終了ã™ã‚‹" #: main/main.cpp scene/main/viewport.cpp msgid "Snap Controls To Pixels" @@ -16462,7 +16425,7 @@ msgstr "オーãƒãƒ¼ã‚µãƒ³ãƒ—リングを使用" #: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp msgid "Active Soft World" -msgstr "" +msgstr "SoftBodyを有効ã«ã™ã‚‹" #: modules/csg/csg_gizmos.cpp msgid "CSG" @@ -16478,11 +16441,11 @@ msgstr "円柱ã®é«˜ã•ã‚’変更" #: modules/csg/csg_gizmos.cpp msgid "Change Torus Inner Radius" -msgstr "トーラスã®å†…径を変更" +msgstr "トーラスã®å†…åŠå¾„を変更" #: modules/csg/csg_gizmos.cpp msgid "Change Torus Outer Radius" -msgstr "トーラスã®å¤–径を変更" +msgstr "トーラスã®å¤–åŠå¾„を変更" #: modules/csg/csg_shape.cpp msgid "Operation" @@ -16546,14 +16509,12 @@ msgid "Cone" msgstr "円éŒ" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Inner Radius" -msgstr "トーラスã®å†…径を変更" +msgstr "内åŠå¾„" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Outer Radius" -msgstr "トーラスã®å¤–径を変更" +msgstr "外åŠå¾„" #: modules/csg/csg_shape.cpp msgid "Ring Sides" @@ -16629,17 +16590,16 @@ msgid "Channel Count" msgstr "ãƒãƒ£ãƒ³ãƒãƒ«ã®æ•°" #: modules/enet/networked_multiplayer_enet.cpp -#, fuzzy msgid "Always Ordered" -msgstr "常ã«ã‚°ãƒªãƒƒãƒ‰ã‚’表示" +msgstr "常ã«é †åºä»˜ã‘ã‚’ã™ã‚‹" #: modules/enet/networked_multiplayer_enet.cpp msgid "Server Relay" -msgstr "" +msgstr "サーãƒãƒ¼ãƒªãƒ¬ãƒ¼" #: modules/enet/networked_multiplayer_enet.cpp msgid "DTLS Verify" -msgstr "" +msgstr "DTLS 検証" #: modules/enet/networked_multiplayer_enet.cpp msgid "DTLS Hostname" @@ -18014,17 +17974,16 @@ msgid "in order:" msgstr "" #: modules/visual_script/visual_script_flow_control.cpp -#, fuzzy msgid "Steps" msgstr "ステップ" #: modules/visual_script/visual_script_flow_control.cpp msgid "Switch" -msgstr "" +msgstr "スイッãƒ" #: modules/visual_script/visual_script_flow_control.cpp msgid "'input' is:" -msgstr "" +msgstr "入力ã¯:" #: modules/visual_script/visual_script_flow_control.cpp msgid "Type Cast" @@ -18273,14 +18232,12 @@ msgid "Construct %s" msgstr "定数" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Get Local Var" -msgstr "ãƒãƒ¼ã‚«ãƒ«ç©ºé–“を使用" +msgstr "ãƒãƒ¼ã‚«ãƒ«å¤‰æ•°ã‚’使用" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Set Local Var" -msgstr "ãƒãƒ¼ã‚«ãƒ«ç©ºé–“を使用" +msgstr "ãƒãƒ¼ã‚«ãƒ«å¤‰æ•°ã‚’セット" #: modules/visual_script/visual_script_nodes.cpp msgid "Action %s" @@ -19552,9 +19509,8 @@ msgstr "コード署å" #: platform/osx/export/export.cpp platform/uwp/export/export.cpp #: platform/windows/export/export.cpp -#, fuzzy msgid "Identity" -msgstr "インデント" +msgstr "è˜åˆ¥å" #: platform/osx/export/export.cpp platform/windows/export/export.cpp #, fuzzy @@ -19752,9 +19708,8 @@ msgid "" msgstr "" #: platform/osx/export/export.cpp platform/windows/export/export.cpp -#, fuzzy msgid "No identity found." -msgstr "アイコンãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" +msgstr "è˜åˆ¥åãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" #: platform/osx/export/export.cpp #, fuzzy @@ -19818,6 +19773,8 @@ msgid "" "Ad-hoc signed applications require the 'Disable Library Validation' " "entitlement to load dynamic libraries." msgstr "" +"アドホック署å付ãアプリケーションã§ã¯ã€å‹•çš„ライブラリをèªã¿è¾¼ã‚€ãŸã‚ã«ã€Œãƒ©ã‚¤" +"ブラリ検証を無効ã«ã™ã‚‹ã€ã®æ¨©é™ãŒå¿…è¦ã§ã™ã€‚" #: platform/osx/export/export.cpp msgid "Code signing bundle" @@ -19848,15 +19805,12 @@ msgid "Sending archive for notarization" msgstr "公証をã™ã‚‹ãŸã‚ã«ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã‚’é€ä¿¡ä¸" #: platform/osx/export/export.cpp -#, fuzzy msgid "ZIP Creation" -msgstr "プãƒã‚¸ã‚§ã‚¯ãƒˆ" +msgstr "ZIP作æˆ" #: platform/osx/export/export.cpp -#, fuzzy msgid "Could not open file to read from path \"%s\"." -msgstr "" -"プãƒã‚¸ã‚§ã‚¯ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’gladleプãƒã‚¸ã‚§ã‚¯ãƒˆã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸ\n" +msgstr "パス \"%s\" ã‹ã‚‰ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã‘ã¾ã›ã‚“ã§ã—ãŸã€‚" #: platform/osx/export/export.cpp msgid "Invalid bundle identifier:" @@ -19867,12 +19821,17 @@ msgid "" "Warning: Built-in \"codesign\" is selected in the Editor Settings. Code " "signing is limited to ad-hoc signature only." msgstr "" +"è¦å‘Š: ビルトインã®ã€Œã‚³ãƒ¼ãƒ‰ç½²åã€ãŒã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼è¨å®šã§é¸æŠžã•ã‚Œã¦ã„ã¾ã™ã€‚コード署" +"åã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã®ã¿ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ã€‚" #: platform/osx/export/export.cpp msgid "" "Warning: Xcode command line tools are not installed, using built-in " "\"codesign\". Code signing is limited to ad-hoc signature only." msgstr "" +"è¦å‘Š: Xcodeã®ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ãƒ„ールãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ãªã„ãŸã‚ã€ãƒ“ルトインã®" +"「コード署åã€ãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚コード署åã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã®ã¿ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾" +"ã™ã€‚" #: platform/osx/export/export.cpp msgid "Notarization: Notarization with an ad-hoc signature is not supported." @@ -19911,17 +19870,19 @@ msgid "" "Code signing is disabled. The exported project will not run on Macs with " "enabled Gatekeeper and Apple Silicon powered Macs." msgstr "" +"コード署åãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚エクスãƒãƒ¼ãƒˆã•ã‚ŒãŸãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆã¯ã€Gatekeeper " +"ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã‚‹ Mac ãŠã‚ˆã³ Apple Silicon æ載㮠Mac ã§ã¯å‹•ä½œã—ã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "" "Hardened Runtime is not compatible with ad-hoc signature, and will be " "disabled!" -msgstr "" +msgstr "Hardened Runtime ã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã¨äº’æ›æ€§ãŒãªã„ãŸã‚ã€ç„¡åŠ¹ã«ãªã‚Šã¾ã™!" #: platform/osx/export/export.cpp msgid "" "Timestamping is not compatible with ad-hoc signature, and will be disabled!" -msgstr "" +msgstr "タイムスタンプã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã¨äº’æ›æ€§ãŒãªã„ãŸã‚ã€ç„¡åŠ¹ã«ãªã‚Šã¾ã™!" #: platform/osx/export/export.cpp msgid "" @@ -19937,34 +19898,46 @@ msgid "" "Privacy: Microphone access is enabled, but usage description is not " "specified." msgstr "" +"プライãƒã‚·ãƒ¼: マイクã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒã‚ã‚Š" +"ã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "" "Privacy: Camera access is enabled, but usage description is not specified." msgstr "" +"プライãƒã‚·ãƒ¼: カメラã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒã‚ã‚Š" +"ã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "" "Privacy: Location information access is enabled, but usage description is " "not specified." msgstr "" +"プライãƒã‚·ãƒ¼: ä½ç½®æƒ…å ±ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒã‚" +"ã‚Šã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "" "Privacy: Address book access is enabled, but usage description is not " "specified." msgstr "" +"プライãƒã‚·ãƒ¼: アドレス帳ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒ" +"ã‚ã‚Šã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "" "Privacy: Calendar access is enabled, but usage description is not specified." msgstr "" +"プライãƒã‚·ãƒ¼: カレンダーã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒ" +"ã‚ã‚Šã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "" "Privacy: Photo library access is enabled, but usage description is not " "specified." msgstr "" +"プライãƒã‚·ãƒ¼:フォトライブラリã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬" +"明ãŒã‚ã‚Šã¾ã›ã‚“。" #: platform/osx/export/export.cpp msgid "macOS" @@ -19972,40 +19945,35 @@ msgstr "macOS" #: platform/osx/export/export.cpp msgid "Force Builtin Codesign" -msgstr "" +msgstr "ビルドインコード署åを強制" #: platform/uwp/export/export.cpp msgid "Architecture" msgstr "アーã‚テクãƒãƒ£" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Display Name" -msgstr "表示スケール" +msgstr "表示å" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Short Name" -msgstr "スクリプトå:" +msgstr "略称" #: platform/uwp/export/export.cpp msgid "Publisher" -msgstr "" +msgstr "パブリッシャー" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Publisher Display Name" -msgstr "パッケージ発行者ã®è¡¨ç¤ºåãŒç„¡åŠ¹ã§ã™ã€‚" +msgstr "パブリッシャー表示å" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Product GUID" -msgstr "無効ãªãƒ—ãƒãƒ€ã‚¯ãƒˆ GUIDã§ã™ã€‚" +msgstr "プãƒãƒ€ã‚¯ãƒˆ GUID" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Publisher GUID" -msgstr "ガイドをクリアã™ã‚‹" +msgstr "パブリッシャー GUID" #: platform/uwp/export/export.cpp msgid "Signing" @@ -20037,73 +20005,71 @@ msgstr "リビジョン" #: platform/uwp/export/export.cpp msgid "Landscape" -msgstr "" +msgstr "ランドスケープ" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Portrait" -msgstr "ãƒãƒ¼ãƒˆ" +msgstr "ãƒãƒ¼ãƒˆãƒ¬ãƒ¼ãƒˆ" #: platform/uwp/export/export.cpp msgid "Landscape Flipped" -msgstr "" +msgstr "ランドスケープå転" #: platform/uwp/export/export.cpp msgid "Portrait Flipped" -msgstr "" +msgstr "ãƒãƒ¼ãƒˆãƒ¬ãƒ¼ãƒˆå転" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Store Logo" -msgstr "スケールモード" +msgstr "ストアãƒã‚´" #: platform/uwp/export/export.cpp msgid "Square 44 X 44 Logo" -msgstr "" +msgstr "æ£æ–¹å½¢ 44 x 44 ãƒã‚´" #: platform/uwp/export/export.cpp msgid "Square 71 X 71 Logo" -msgstr "" +msgstr "æ£æ–¹å½¢ 71 x 71 ãƒã‚´" #: platform/uwp/export/export.cpp msgid "Square 150 X 150 Logo" -msgstr "" +msgstr "æ£æ–¹å½¢ 150 x 150 ãƒã‚´" #: platform/uwp/export/export.cpp msgid "Square 310 X 310 Logo" -msgstr "" +msgstr "æ£æ–¹å½¢ 310 x 310 ãƒã‚´" #: platform/uwp/export/export.cpp msgid "Wide 310 X 150 Logo" -msgstr "" +msgstr "ワイド 310 x 150 ãƒã‚´" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Splash Screen" -msgstr "ドãƒãƒ¼ã‚³ãƒ¼ãƒ«:" +msgstr "スプラッシュ・スクリーン" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Tiles" -msgstr "ファイル" +msgstr "タイル" #: platform/uwp/export/export.cpp msgid "Show Name On Square 150 X 150" -msgstr "" +msgstr "æ£æ–¹å½¢ 150×150 表示å" #: platform/uwp/export/export.cpp msgid "Show Name On Wide 310 X 150" -msgstr "" +msgstr "ワイド 310x150 表示å" #: platform/uwp/export/export.cpp msgid "Show Name On Square 310 X 310" -msgstr "" +msgstr "æ£æ–¹å½¢ 310×310 表示å" #: platform/uwp/export/export.cpp msgid "" "Godot's Mono version does not support the UWP platform. Use the standard " "build (no C# support) if you wish to target UWP." msgstr "" +"Godot ã® Mono ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯ UWP プラットフォームをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。UWP ã‚’" +"対象ã¨ã—ãŸã„å ´åˆã¯ã€æ¨™æº–ビルド(C# éžã‚µãƒãƒ¼ãƒˆ)を使用ã—ã¦ä¸‹ã•ã„。" #: platform/uwp/export/export.cpp msgid "Invalid package short name." @@ -20169,41 +20135,36 @@ msgid "UWP" msgstr "UWP" #: platform/uwp/export/export.cpp platform/windows/export/export.cpp -#, fuzzy msgid "Signtool" -msgstr "シグナル" +msgstr "サインツール" #: platform/uwp/export/export.cpp msgid "Debug Certificate" -msgstr "" +msgstr "デãƒãƒƒã‚°è¨¼æ˜Žæ›¸" #: platform/uwp/export/export.cpp -#, fuzzy msgid "Debug Algorithm" -msgstr "デãƒãƒƒã‚¬ãƒ¼" +msgstr "デãƒãƒƒã‚°ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ " #: platform/windows/export/export.cpp -#, fuzzy msgid "Failed to rename temporary file \"%s\"." -msgstr "一時ファイルを削除ã§ãã¾ã›ã‚“:" +msgstr "一時ファイル \"%s\" ã®åå‰ã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸã€‚" #: platform/windows/export/export.cpp msgid "Identity Type" -msgstr "" +msgstr "è˜åˆ¥åタイプ" #: platform/windows/export/export.cpp msgid "Timestamp Server URL" -msgstr "" +msgstr "タイムスタンプサーãƒãƒ¼URL" #: platform/windows/export/export.cpp -#, fuzzy msgid "Digest Algorithm" -msgstr "デãƒãƒƒã‚¬ãƒ¼" +msgstr "ダイジェストアルゴリズム" #: platform/windows/export/export.cpp -#, fuzzy msgid "Modify Resources" -msgstr "リソースをコピー" +msgstr "リソースã®å¤‰æ›´" #: platform/windows/export/export.cpp msgid "File Version" @@ -20227,22 +20188,19 @@ msgstr "ファイルã®èª¬æ˜Ž" #: platform/windows/export/export.cpp msgid "Trademarks" -msgstr "" +msgstr "商標" #: platform/windows/export/export.cpp -#, fuzzy msgid "Resources Modification" -msgstr "ランダムãªå›žè»¢:" +msgstr "リソースã®å¤‰æ›´" #: platform/windows/export/export.cpp -#, fuzzy msgid "Could not find rcedit executable at \"%s\"." -msgstr "ã‚ーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。" +msgstr "\"%s\" ã« rcedit 実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" #: platform/windows/export/export.cpp -#, fuzzy msgid "Could not find wine executable at \"%s\"." -msgstr "ã‚ーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。" +msgstr "\"%s\" ã« wine 実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" #: platform/windows/export/export.cpp msgid "" @@ -20250,31 +20208,29 @@ msgid "" "Settings (Export > Windows > Rcedit), or disable \"Application > Modify " "Resources\" in the export preset." msgstr "" +"rcedit 実行ファイルを開始ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚エディターè¨å®š (Export > Windows " +"> Rcedit)ã‹ã‚‰ rcedit ã®ãƒ‘スをè¨å®šã™ã‚‹ã‹ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ—リセット㧠\"アプリ" +"ケーション > リソースã®å¤‰æ›´\"を無効ã«ã—ã¦ä¸‹ã•ã„。" #: platform/windows/export/export.cpp -#, fuzzy msgid "rcedit failed to modify executable: %s." -msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™ã€‚" +msgstr "rcedit ã¯å®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸ: %s。" #: platform/windows/export/export.cpp -#, fuzzy msgid "Could not find signtool executable at \"%s\"." -msgstr "ã‚ーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。" +msgstr "\"%s\" 㫠サインツール実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" #: platform/windows/export/export.cpp -#, fuzzy msgid "Could not find osslsigncode executable at \"%s\"." -msgstr "ã‚ーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。" +msgstr "\"%s\" ã« osslsigncode 実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" #: platform/windows/export/export.cpp -#, fuzzy msgid "Invalid identity type." -msgstr "無効ãªè˜åˆ¥å:" +msgstr "無効ãªè˜åˆ¥åタイプ。" #: platform/windows/export/export.cpp -#, fuzzy msgid "Invalid timestamp server." -msgstr "無効ãªåå‰ã§ã™ã€‚" +msgstr "タイムスタンプサーãƒãƒ¼ãŒç„¡åŠ¹ã§ã™ã€‚" #: platform/windows/export/export.cpp msgid "" @@ -20282,22 +20238,25 @@ msgid "" "Settings (Export > Windows > Signtool), or disable \"Codesign\" in the " "export preset." msgstr "" +"サインツール実行ファイルを開始ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚エディターè¨å®š (Export > " +"Windows > サインツール)ã‹ã‚‰ã‚µã‚¤ãƒ³ãƒ„ールã®ãƒ‘スをè¨å®šã™ã‚‹ã‹ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ—リ" +"セット㧠\"コード署å\"を無効ã«ã—ã¦ä¸‹ã•ã„。" #: platform/windows/export/export.cpp -#, fuzzy msgid "Signtool failed to sign executable: %s." -msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™ã€‚" +msgstr "サインツールã¯å®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã®ç½²åã«å¤±æ•—ã—ã¾ã—ãŸ: %s。" #: platform/windows/export/export.cpp -#, fuzzy msgid "Failed to remove temporary file \"%s\"." -msgstr "一時ファイルを削除ã§ãã¾ã›ã‚“:" +msgstr "一時ファイル \"%s\" ã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚" #: platform/windows/export/export.cpp msgid "" "The rcedit tool must be configured in the Editor Settings (Export > Windows " "> Rcedit) to change the icon or app information data." msgstr "" +"ã‚¢ã‚¤ã‚³ãƒ³ã‚„ã‚¢ãƒ—ãƒªæƒ…å ±ãƒ‡ãƒ¼ã‚¿ã‚’å¤‰æ›´ã™ã‚‹ã«ã¯ã€ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼è¨å®š (Export > Windows > " +"Rcedit) 㧠rcedit ã®è¨å®šã‚’è¡Œã†å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚" #: platform/windows/export/export.cpp msgid "Invalid icon path:" @@ -20313,20 +20272,19 @@ msgstr "無効ãªè£½å“ãƒãƒ¼ã‚¸ãƒ§ãƒ³:" #: platform/windows/export/export.cpp msgid "Windows executables cannot be >= 4 GiB." -msgstr "" +msgstr "Windows ã®å®Ÿè¡Œãƒ•ã‚¡ã‚¤ãƒ«ã¯ã€4GiBを超ãˆã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。" #: platform/windows/export/export.cpp platform/x11/export/export.cpp -#, fuzzy msgid "Failed to open executable file \"%s\"." -msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™ã€‚" +msgstr "実行ファイル \"%s\" ã‚’é–‹ãã®ã«å¤±æ•—ã—ã¾ã—ãŸã€‚" #: platform/windows/export/export.cpp platform/x11/export/export.cpp msgid "Executable file header corrupted." -msgstr "" +msgstr "実行ファイルã®ãƒ˜ãƒƒãƒ€ãƒ¼ãŒç ´æã—ã¦ã„ã¾ã™ã€‚" #: platform/windows/export/export.cpp platform/x11/export/export.cpp msgid "Executable \"pck\" section not found." -msgstr "" +msgstr "実行å¯èƒ½ãª \"pck \"セクションãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。" #: platform/windows/export/export.cpp msgid "Windows" @@ -20334,7 +20292,7 @@ msgstr "Windows" #: platform/windows/export/export.cpp msgid "Rcedit" -msgstr "" +msgstr "Rcedit" #: platform/windows/export/export.cpp msgid "Osslsigncode" @@ -20363,21 +20321,18 @@ msgstr "" #: scene/2d/animated_sprite.cpp scene/2d/cpu_particles_2d.cpp #: scene/2d/particles_2d.cpp scene/3d/cpu_particles.cpp scene/3d/particles.cpp -#, fuzzy msgid "Speed Scale" -msgstr "スケール" +msgstr "スピードスケール" #: scene/2d/animated_sprite.cpp scene/2d/audio_stream_player_2d.cpp #: scene/3d/audio_stream_player_3d.cpp scene/3d/sprite_3d.cpp #: scene/audio/audio_stream_player.cpp -#, fuzzy msgid "Playing" -msgstr "実行" +msgstr "実行ä¸" #: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp -#, fuzzy msgid "Centered" -msgstr "ä¸å¤®" +msgstr "ä¸å¤®æƒãˆ" #: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp #: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp @@ -20390,52 +20345,45 @@ msgid "Flip V" msgstr "åž‚ç›´å転" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Monitoring" -msgstr "モニター" +msgstr "モニタリング" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Monitorable" -msgstr "モニター" +msgstr "モニターå¯èƒ½" #: scene/2d/area_2d.cpp scene/3d/area.cpp msgid "Physics Overrides" msgstr "物ç†ã®ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Space Override" -msgstr "上書ã" +msgstr "é ˜åŸŸã®ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Gravity Point" -msgstr "ãƒã‚¤ãƒ³ãƒˆã‚’生æˆ" +msgstr "é‡åŠ›ç‚¹" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Gravity Distance Scale" -msgstr "インスタンス" +msgstr "é‡åŠ›è·é›¢ã‚¹ã‚±ãƒ¼ãƒ«" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Gravity Vec" -msgstr "デフォルトã®ãƒ—レビュー" +msgstr "é‡åŠ›ãƒ™ã‚¯ãƒˆãƒ«" #: scene/2d/area_2d.cpp scene/2d/cpu_particles_2d.cpp scene/3d/area.cpp #: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp msgid "Gravity" -msgstr "" +msgstr "é‡åŠ›" #: scene/2d/area_2d.cpp scene/3d/area.cpp -#, fuzzy msgid "Linear Damp" -msgstr "リニア" +msgstr "線形減衰" #: scene/2d/area_2d.cpp scene/3d/area.cpp msgid "Angular Damp" -msgstr "" +msgstr "角度減衰" #: scene/2d/area_2d.cpp scene/3d/area.cpp msgid "Audio Bus" @@ -20453,9 +20401,8 @@ msgstr "ボリュームdB" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/audio/audio_stream_player.cpp #: servers/audio/effects/audio_effect_pitch_shift.cpp -#, fuzzy msgid "Pitch Scale" -msgstr "スケール" +msgstr "ピッãƒã‚¹ã‚±ãƒ¼ãƒ«" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp @@ -20465,7 +20412,7 @@ msgstr "自動å†ç”Ÿ" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/audio/audio_stream_player.cpp msgid "Stream Paused" -msgstr "" +msgstr "ストリームã®ä¸€æ™‚åœæ¢" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/3d/light.cpp scene/3d/reflection_probe.cpp @@ -20475,9 +20422,8 @@ msgid "Max Distance" msgstr "最大è·é›¢" #: scene/2d/audio_stream_player_2d.cpp scene/3d/light.cpp -#, fuzzy msgid "Attenuation" -msgstr "アニメーション" +msgstr "減衰é‡" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp @@ -20486,22 +20432,19 @@ msgstr "ãƒã‚¹" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp msgid "Area Mask" -msgstr "" +msgstr "エリアマスク" #: scene/2d/back_buffer_copy.cpp -#, fuzzy msgid "Copy Mode" -msgstr "ノードをコピー" +msgstr "コピーモード" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Anchor Mode" -msgstr "アイコンモード" +msgstr "アンカーモード" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Rotating" -msgstr "回転ã®ã‚¹ãƒ†ãƒƒãƒ—:" +msgstr "回転" #: scene/2d/camera_2d.cpp scene/2d/listener_2d.cpp scene/3d/camera.cpp #: scene/3d/listener.cpp scene/animation/animation_blend_tree.cpp @@ -20513,9 +20456,8 @@ msgid "Zoom" msgstr "ズーム" #: scene/2d/camera_2d.cpp scene/main/canvas_layer.cpp -#, fuzzy msgid "Custom Viewport" -msgstr "1 ビューãƒãƒ¼ãƒˆ" +msgstr "カスタムビューãƒãƒ¼ãƒˆ" #: scene/2d/camera_2d.cpp scene/3d/camera.cpp scene/3d/interpolated_camera.cpp #: scene/animation/animation_player.cpp scene/animation/animation_tree.cpp @@ -20544,29 +20486,24 @@ msgid "Bottom" msgstr "下" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Smoothed" -msgstr "スムーズステップ" +msgstr "スムージング" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Draw Margin" -msgstr "マージンをè¨å®šã™ã‚‹" +msgstr "マージンをæç”»ã™ã‚‹" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Drag Margin H Enabled" -msgstr "マージンをè¨å®šã™ã‚‹" +msgstr "水平方å‘ã®ãƒ‰ãƒ©ãƒƒã‚°ãƒžãƒ¼ã‚¸ãƒ³ã«ã®ã¿æœ‰åŠ¹" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Drag Margin V Enabled" -msgstr "マージンをè¨å®šã™ã‚‹" +msgstr "åž‚ç›´æ–¹å‘ã®ãƒ‰ãƒ©ãƒƒã‚°ãƒžãƒ¼ã‚¸ãƒ³ã«ã®ã¿æœ‰åŠ¹" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Smoothing" -msgstr "スムーズステップ" +msgstr "スムージング" #: scene/2d/camera_2d.cpp msgid "H" @@ -20577,35 +20514,29 @@ msgid "V" msgstr "åž‚ç›´" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Drag Margin" -msgstr "マージンをè¨å®šã™ã‚‹" +msgstr "ドラッグマージン" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Draw Screen" -msgstr "ドãƒãƒ¼ã‚³ãƒ¼ãƒ«:" +msgstr "スクリーンをæç”»ã™ã‚‹" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Draw Limits" -msgstr "ドãƒãƒ¼ã‚³ãƒ¼ãƒ«:" +msgstr "é™ç•Œã‚’æç”»ã™ã‚‹" #: scene/2d/camera_2d.cpp -#, fuzzy msgid "Draw Drag Margin" -msgstr "マージンをè¨å®šã™ã‚‹" +msgstr "ドラッグマージンをæç”»ã™ã‚‹" #: scene/2d/canvas_item.cpp scene/resources/environment.cpp #: scene/resources/material.cpp -#, fuzzy msgid "Blend Mode" -msgstr "ブレンド2 ノード" +msgstr "ブレンドモード" #: scene/2d/canvas_item.cpp -#, fuzzy msgid "Light Mode" -msgstr "å³ä¼¸é•·" +msgstr "ライトモード" #: scene/2d/canvas_item.cpp #, fuzzy @@ -23582,14 +23513,12 @@ msgid "AABB" msgstr "" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Sorting" msgstr "ソート" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Use AABB Center" -msgstr "アンビエントを使用" +msgstr "AABBセンターを使用" #: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp #, fuzzy diff --git a/editor/translations/ka.po b/editor/translations/ka.po index 629afaa429..ce7502e5ac 100644 --- a/editor/translations/ka.po +++ b/editor/translations/ka.po @@ -11066,7 +11066,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/km.po b/editor/translations/km.po index ade147ec7e..85f5081b6f 100644 --- a/editor/translations/km.po +++ b/editor/translations/km.po @@ -10598,7 +10598,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/ko.po b/editor/translations/ko.po index f43830b1e9..9563bc6244 100644 --- a/editor/translations/ko.po +++ b/editor/translations/ko.po @@ -29,7 +29,7 @@ # ì‹ ë™ê·œ <rlsl0422@gmail.com>, 2021. # Kiroo <elusive1102@naver.com>, 2021. # JumpJetAvocado <dwkng@jbnu.ac.kr>, 2021. -# Lee Minhak <minarihak@gmail.com>, 2022. +# Lee Minhak <minarihak@gmail.com>, 2022, 2023. # 한수현 <shh1473@ajou.ac.kr>, 2022. # Taehun Yun <yooontehoon@naver.com>, 2022. # vrSono <global.sonogong@gmail.com>, 2022. @@ -41,13 +41,14 @@ # nulltable <un5450@naver.com>, 2022. # Godoto <aicompose@gmail.com>, 2022. # gaenyang <gaenyang@outlook.com>, 2022. +# 오지훈 <jule1130@naver.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-10-24 12:41+0000\n" -"Last-Translator: Godoto <aicompose@gmail.com>\n" +"PO-Revision-Date: 2023-01-20 10:19+0000\n" +"Last-Translator: 오지훈 <jule1130@naver.com>\n" "Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/" "godot/ko/>\n" "Language: ko\n" @@ -55,7 +56,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.14.2-dev\n" +"X-Generator: Weblate 4.15.1\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -582,7 +583,7 @@ msgstr "ì´ë¦„" #: modules/visual_script/visual_script_nodes.cpp platform/uwp/export/export.cpp #: platform/windows/export/export.cpp msgid "Description" -msgstr "ì„œìˆ " +msgstr "설명" #: core/project_settings.cpp editor/editor_node.cpp editor/editor_settings.cpp #: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp @@ -10886,7 +10887,7 @@ msgstr "후면 ì›ê·¼" msgid " [auto]" msgstr " [ìžë™]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [í¬í„¸ 활성]" @@ -17852,9 +17853,8 @@ msgid "Use Default Args" msgstr "ë””í´íŠ¸ë¡œ ìž¬ì„¤ì •" #: modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "Validate" -msgstr "올바른 문ìž:" +msgstr "올바른 문ìž" #: modules/visual_script/visual_script_func_nodes.cpp #, fuzzy @@ -17984,24 +17984,20 @@ msgid "Preload" msgstr "ìƒˆë¡œê³ ì¹¨" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Get Index" -msgstr "Z ì¸ë±ìŠ¤" +msgstr "ì¸ë±ìŠ¤ ê°€ì ¸ì˜¤ê¸°" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Set Index" -msgstr "Z ì¸ë±ìŠ¤" +msgstr "ì¸ë±ìŠ¤ ì„¤ì •" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Global Constant" -msgstr "ìƒìˆ˜" +msgstr "ì „ì— ìƒìˆ˜" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Class Constant" -msgstr "ìƒìˆ˜" +msgstr "í´ëž˜ìŠ¤ ìƒìˆ˜" #: modules/visual_script/visual_script_nodes.cpp #, fuzzy @@ -18009,24 +18005,21 @@ msgid "Basic Constant" msgstr "ìƒìˆ˜" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Math Constant" -msgstr "ìƒìˆ˜" +msgstr "수학 ìƒìˆ˜" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Get Engine Singleton" -msgstr "í™œì„±í™”ëœ GDNative 싱글톤" +msgstr "엔진 싱글톤 ê°€ì ¸ì˜¤ê¸°" #: modules/visual_script/visual_script_nodes.cpp #, fuzzy msgid "Get Scene Node" -msgstr "시간 íƒìƒ‰ 노드" +msgstr "씬 Node ê°€ì ¸ì˜¤ê¸°" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "Get Scene Tree" -msgstr "씬 트리 편집" +msgstr "씬 트리 ê°€ì ¸ì˜¤ê¸°" #: modules/visual_script/visual_script_nodes.cpp #, fuzzy @@ -18034,9 +18027,8 @@ msgid "Get Self" msgstr "ìžì²´" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "CustomNode" -msgstr "노드 잘ë¼ë‚´ê¸°" +msgstr "" #: modules/visual_script/visual_script_nodes.cpp msgid "Custom node has no _step() method, can't process graph." @@ -18096,18 +18088,16 @@ msgid "Wait" msgstr "대기" #: modules/visual_script/visual_script_yield_nodes.cpp -#, fuzzy msgid "Next Frame" -msgstr "í”„ë ˆìž„ ì´ë™" +msgstr "ë‹¤ìŒ í”„ë ˆìž„" #: modules/visual_script/visual_script_yield_nodes.cpp -#, fuzzy msgid "Next Physics Frame" -msgstr "물리 í”„ë ˆìž„ %" +msgstr "ë‹¤ìŒ ë¬¼ë¦¬ í”„ë ˆìž„" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "%s sec(s)" -msgstr "" +msgstr "%sì´ˆ" #: modules/visual_script/visual_script_yield_nodes.cpp scene/main/timer.cpp #, fuzzy @@ -18136,7 +18126,7 @@ msgstr "ìš°ì„ ìˆœìœ„ 모드" #: modules/webrtc/webrtc_data_channel.h msgid "WebRTC" -msgstr "" +msgstr "WebRTC" #: modules/webrtc/webrtc_data_channel.h msgid "Max Channel In Buffer (KB)" @@ -18148,12 +18138,12 @@ msgstr "" #: modules/websocket/websocket_client.cpp msgid "Trusted SSL Certificate" -msgstr "" +msgstr "ì‹ ë¢°í• ìˆ˜ 있는 SSL ì¸ì¦ì„œ" #: modules/websocket/websocket_macros.h #, fuzzy msgid "WebSocket Client" -msgstr "ë„¤íŠ¸ì›Œí¬ í”„ë¡œíŒŒì¼ëŸ¬" +msgstr "WebSocket í´ë¼ì´ì–¸íŠ¸" #: modules/websocket/websocket_macros.h msgid "Max In Buffer (KB)" @@ -18181,13 +18171,12 @@ msgid "Bind IP" msgstr "" #: modules/websocket/websocket_server.cpp -#, fuzzy msgid "Private Key" -msgstr "물리 키" +msgstr "ê°œì¸ í‚¤" #: modules/websocket/websocket_server.cpp platform/javascript/export/export.cpp msgid "SSL Certificate" -msgstr "" +msgstr "SSL ì¸ì¦ì„œ" #: modules/websocket/websocket_server.cpp #, fuzzy @@ -18212,8 +18201,9 @@ msgid "Optional Features" msgstr "ì„ íƒì 기능" #: modules/webxr/webxr_interface.cpp +#, fuzzy msgid "Requested Reference Space Types" -msgstr "" +msgstr "ìš”ì²ëœ 참조 공간 ìœ í˜•" #: modules/webxr/webxr_interface.cpp msgid "Reference Space Type" diff --git a/editor/translations/lt.po b/editor/translations/lt.po index 5f0c068dbb..33cc2f8ae9 100644 --- a/editor/translations/lt.po +++ b/editor/translations/lt.po @@ -11054,7 +11054,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/lv.po b/editor/translations/lv.po index 51836c627b..18c5c4242e 100644 --- a/editor/translations/lv.po +++ b/editor/translations/lv.po @@ -10997,7 +10997,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/mk.po b/editor/translations/mk.po index 6d725ac82b..9f06f03d81 100644 --- a/editor/translations/mk.po +++ b/editor/translations/mk.po @@ -10624,7 +10624,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/ml.po b/editor/translations/ml.po index 171cc17fdb..8a66f8b8b4 100644 --- a/editor/translations/ml.po +++ b/editor/translations/ml.po @@ -10647,7 +10647,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/mr.po b/editor/translations/mr.po index 24300da41a..ac50228677 100644 --- a/editor/translations/mr.po +++ b/editor/translations/mr.po @@ -10634,7 +10634,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/ms.po b/editor/translations/ms.po index 3b34efe6f2..7c87a4709d 100644 --- a/editor/translations/ms.po +++ b/editor/translations/ms.po @@ -11073,7 +11073,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/nb.po b/editor/translations/nb.po index 9d831aee5d..f7aac38f70 100644 --- a/editor/translations/nb.po +++ b/editor/translations/nb.po @@ -4,7 +4,7 @@ # This file is distributed under the same license as the Godot source code. # Allan Nordhøy <epost@anotheragency.no>, 2017-2018, 2019, 2020, 2021. # Anonymous <GentleSaucepan@protonmail.com>, 2017, 2021. -# Elias <eliasnykrem@gmail.com>, 2018. +# Elias <eliasnykrem@gmail.com>, 2018, 2023. # flesk <eivindkn@gmail.com>, 2017, 2019. # Frank T. Rambol <frank@d-fect.com>, 2018, 2021. # Jørgen Aarmo Lund <jorgen.aarmo@gmail.com>, 2016, 2019. @@ -28,8 +28,8 @@ msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-12-08 10:28+0000\n" -"Last-Translator: slasken06 <ask.skivdal@gmail.com>\n" +"PO-Revision-Date: 2023-01-17 13:54+0000\n" +"Last-Translator: Elias <eliasnykrem@gmail.com>\n" "Language-Team: Norwegian BokmÃ¥l <https://hosted.weblate.org/projects/godot-" "engine/godot/nb_NO/>\n" "Language: nb\n" @@ -37,7 +37,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -2281,7 +2281,7 @@ msgstr "Ã…pne" #: editor/dependency_editor.cpp msgid "Owners of: %s (Total: %d)" -msgstr "" +msgstr "Eiere av: %s (Totalt: %d)" #: editor/dependency_editor.cpp #, fuzzy @@ -2868,22 +2868,19 @@ msgstr "Velg" #: editor/editor_export.cpp msgid "Project export for platform:" -msgstr "" +msgstr "Prosjekteksport til platform:" #: editor/editor_export.cpp -#, fuzzy msgid "Completed with warnings." -msgstr "Kopier Node-bane" +msgstr "Fullført med varsler." #: editor/editor_export.cpp -#, fuzzy msgid "Completed successfully." -msgstr "Vellykket Installering av Pakke!" +msgstr "Fullført vellykket." #: editor/editor_export.cpp -#, fuzzy msgid "Failed." -msgstr "Feilet:" +msgstr "Feilet." #: editor/editor_export.cpp msgid "Storing File:" @@ -2898,29 +2895,24 @@ msgid "Packing" msgstr "Pakking" #: editor/editor_export.cpp -#, fuzzy msgid "Save PCK" -msgstr "Lagre som" +msgstr "Lagre PCK" #: editor/editor_export.cpp -#, fuzzy msgid "Cannot create file \"%s\"." -msgstr "Kunne ikke opprette mappe." +msgstr "Kunne ikke opprette filen \"%s\"." #: editor/editor_export.cpp -#, fuzzy msgid "Failed to export project files." -msgstr "Kunne ikke opprette mappe." +msgstr "Kunne ikke eksportere prosjektfiler." #: editor/editor_export.cpp -#, fuzzy msgid "Can't open file to read from path \"%s\"." -msgstr "Kan ikke Ã¥pne fil for skriving:" +msgstr "Kan ikke Ã¥pne filen for Ã¥ lese fra banen \"%s\"." #: editor/editor_export.cpp -#, fuzzy msgid "Save ZIP" -msgstr "Lagre som" +msgstr "Lagre ZIP" #: editor/editor_export.cpp msgid "" @@ -2984,9 +2976,8 @@ msgstr "" #: editor/editor_export.cpp platform/android/export/export_plugin.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp #: platform/osx/export/export.cpp platform/uwp/export/export.cpp -#, fuzzy msgid "Custom Template" -msgstr "Medlemmer" +msgstr "Egendefinert mal" #: editor/editor_export.cpp editor/project_export.cpp #: platform/android/export/export_plugin.cpp platform/iphone/export/export.cpp @@ -2996,22 +2987,20 @@ msgid "Release" msgstr "Slipp" #: editor/editor_export.cpp -#, fuzzy msgid "Binary Format" -msgstr "Anim Forandre Omforming" +msgstr "Binærformat" #: editor/editor_export.cpp msgid "64 Bits" -msgstr "" +msgstr "64 Bits" #: editor/editor_export.cpp msgid "Embed PCK" -msgstr "" +msgstr "Innebygd PCK" #: editor/editor_export.cpp platform/osx/export/export.cpp -#, fuzzy msgid "Texture Format" -msgstr "Linjal Modus" +msgstr "Teksturformat" #: editor/editor_export.cpp msgid "BPTC" @@ -3031,9 +3020,8 @@ msgid "ETC2" msgstr "" #: editor/editor_export.cpp -#, fuzzy msgid "No BPTC Fallbacks" -msgstr "Tilbakefall" +msgstr "Ingen BPTC tilbakefall" #: editor/editor_export.cpp platform/android/export/export_plugin.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -3048,24 +3036,20 @@ msgid "Custom release template not found." msgstr "Fant ikke tilpasset utgivelsesmal." #: editor/editor_export.cpp -#, fuzzy msgid "Prepare Template" -msgstr "HÃ¥ndter Eksportmaler" +msgstr "Forbered mal" #: editor/editor_export.cpp platform/osx/export/export.cpp -#, fuzzy msgid "The given export path doesn't exist." -msgstr "Fil eksisterer ikke." +msgstr "Den angitte eksportbanen eksisterer ikke." #: editor/editor_export.cpp platform/javascript/export/export.cpp -#, fuzzy msgid "Template file not found: \"%s\"." -msgstr "Malfil ble ikke funnet:" +msgstr "Malfil ble ikke funnet \"%s\"." #: editor/editor_export.cpp -#, fuzzy msgid "Failed to copy export template." -msgstr "HÃ¥ndter Eksportmaler" +msgstr "Kunne ikke kopiere eksportmalen." #: editor/editor_export.cpp platform/windows/export/export.cpp #: platform/x11/export/export.cpp @@ -3082,9 +3066,8 @@ msgid "Convert Text Resources To Binary On Export" msgstr "" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "3D Editor" -msgstr "Redigeringsverktøy" +msgstr "3D Redigeringsverktøy" #: editor/editor_feature_profile.cpp msgid "Script Editor" @@ -3097,7 +3080,7 @@ msgstr "Ressursbibliotek" #: editor/editor_feature_profile.cpp msgid "Scene Tree Editing" -msgstr "" +msgstr "Scenetre redigering" #: editor/editor_feature_profile.cpp #, fuzzy @@ -3115,7 +3098,7 @@ msgstr "Importer" #: editor/editor_feature_profile.cpp msgid "Allows to view and edit 3D scenes." -msgstr "" +msgstr "Lar deg se og redigere 3D scener." #: editor/editor_feature_profile.cpp msgid "Allows to edit scripts using the integrated script editor." @@ -11529,7 +11512,7 @@ msgstr "Perspektiv" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" @@ -14991,9 +14974,8 @@ msgid "Project Path:" msgstr "Prosjektsti:" #: editor/project_manager.cpp -#, fuzzy msgid "Project Installation Path:" -msgstr "Prosjektsti:" +msgstr "Prosjekt installasjonsti:" #: editor/project_manager.cpp msgid "Renderer:" @@ -15005,7 +14987,7 @@ msgstr "" #: editor/project_manager.cpp msgid "Not supported by your GPU drivers." -msgstr "" +msgstr "Støttes ikke av dine GPU-drivere." #: editor/project_manager.cpp msgid "" @@ -15040,9 +15022,8 @@ msgid "Renderer can be changed later, but scenes may need to be adjusted." msgstr "Rendrer kan endres senere, men scener mÃ¥ kanskje justeres." #: editor/project_manager.cpp -#, fuzzy msgid "Missing Project" -msgstr "Importer Eksisterende Prosjekt" +msgstr "Manglede Prosjekt" #: editor/project_manager.cpp msgid "Error: Project is missing on the filesystem." @@ -15053,9 +15034,8 @@ msgid "Local" msgstr "Lokal" #: editor/project_manager.cpp -#, fuzzy msgid "Local Projects" -msgstr "Prosjekter" +msgstr "Lokale prosjekter" #: editor/project_manager.cpp #, fuzzy @@ -15063,9 +15043,8 @@ msgid "Asset Library Projects" msgstr "Ressursbibliotek" #: editor/project_manager.cpp -#, fuzzy msgid "Can't open project at '%s'." -msgstr "Kan ikke Ã¥pne prosjekt" +msgstr "Kan ikke Ã¥pne prosjektet i '%s'." #: editor/project_manager.cpp msgid "Are you sure to open more than one project?" @@ -15172,23 +15151,20 @@ msgid "Loading, please wait..." msgstr "Henter fillager, vennligst vent..." #: editor/project_manager.cpp -#, fuzzy msgid "Edit Project" -msgstr "Eksporter Prosjekt" +msgstr "Rediger Prosjekt" #: editor/project_manager.cpp -#, fuzzy msgid "Run Project" -msgstr "Endre Navn pÃ¥ Prosjekt" +msgstr "Kjør prosjektet" #: editor/project_manager.cpp msgid "Scan" -msgstr "Skann" +msgstr "Søk" #: editor/project_manager.cpp -#, fuzzy msgid "Scan Projects" -msgstr "Prosjekter" +msgstr "Søk etter prosjekter" #: editor/project_manager.cpp msgid "Select a Folder to Scan" @@ -15199,19 +15175,16 @@ msgid "New Project" msgstr "Nytt prosjekt" #: editor/project_manager.cpp -#, fuzzy msgid "Import Project" -msgstr "Eksporter Prosjekt" +msgstr "Importert prosjekt" #: editor/project_manager.cpp -#, fuzzy msgid "Remove Project" -msgstr "Endre Navn pÃ¥ Prosjekt" +msgstr "Fjern prosjekt" #: editor/project_manager.cpp -#, fuzzy msgid "Remove Missing" -msgstr "Fjern punkt" +msgstr "Fjern manglende" #: editor/project_manager.cpp msgid "About" @@ -15227,7 +15200,7 @@ msgstr "Fjern alle" #: editor/project_manager.cpp msgid "Also delete project contents (no undo!)" -msgstr "" +msgstr "Slett ogsÃ¥ prosjektets innhold (kan ikke reverseres!)" #: editor/project_manager.cpp msgid "Can't run project" @@ -15240,9 +15213,8 @@ msgid "" msgstr "" #: editor/project_manager.cpp -#, fuzzy msgid "Filter projects" -msgstr "Lim inn Noder" +msgstr "Filtre prosjekter" #: editor/project_manager.cpp msgid "" diff --git a/editor/translations/nl.po b/editor/translations/nl.po index 5e80c53732..0e47306f0d 100644 --- a/editor/translations/nl.po +++ b/editor/translations/nl.po @@ -11327,7 +11327,7 @@ msgstr "Perspectief" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/pl.po b/editor/translations/pl.po index 47b7bfe98a..31048d3390 100644 --- a/editor/translations/pl.po +++ b/editor/translations/pl.po @@ -2,7 +2,7 @@ # Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). # This file is distributed under the same license as the Godot source code. -# 8-bit Pixel <dawdejw@gmail.com>, 2016. +# 8-bit Pixel <dawdejw@gmail.com>, 2016, 2023. # Adam Wolanski <adam.wolanski94@gmail.com>, 2017. # Adrian WÄ™cÅ‚awski <weclawskiadrian@gmail.com>, 2016. # aelspire <aelspire@gmail.com>, 2017, 2019, 2020, 2021. @@ -17,14 +17,14 @@ # Maksymilian Åšwiąć <maksymilian.swiac@gmail.com>, 2017-2018. # Mietek SzczeÅ›niak <ravaging@go2.pl>, 2016. # NeverK <neverkoxu@gmail.com>, 2018, 2019, 2020, 2021, 2022. -# Rafal Brozio <rafal.brozio@gmail.com>, 2016, 2019, 2020, 2021. +# Rafal Brozio <rafal.brozio@gmail.com>, 2016, 2019, 2020, 2021, 2023. # RafaÅ‚ Ziemniak <synaptykq@gmail.com>, 2017. -# RM <synaptykq@gmail.com>, 2018, 2020, 2022. +# RM <synaptykq@gmail.com>, 2018, 2020, 2022, 2023. # Sebastian Krzyszkowiak <dos@dosowisko.net>, 2017. -# Sebastian Pasich <sebastian.pasich@gmail.com>, 2017, 2019, 2020, 2022. +# Sebastian Pasich <sebastian.pasich@gmail.com>, 2017, 2019, 2020, 2022, 2023. # siatek papieros <sbigneu@gmail.com>, 2016. # Zatherz <zatherz@linux.pl>, 2017, 2020, 2021. -# Tomek <kobewi4e@gmail.com>, 2018, 2019, 2020, 2021, 2022. +# Tomek <kobewi4e@gmail.com>, 2018, 2019, 2020, 2021, 2022, 2023. # Wojcieh Er Zet <wojcieh.rzepecki@gmail.com>, 2018. # Dariusz Siek <dariuszynski@gmail.com>, 2018, 2019, 2020, 2021. # Szymon Nowakowski <smnbdg13@gmail.com>, 2019. @@ -45,7 +45,7 @@ # Piotr Grodzki <ziemniakglados@gmail.com>, 2020. # Dzejkop <jakubtrad@gmail.com>, 2020, 2021. # Mateusz Grzonka <alpinus4@gmail.com>, 2020. -# gnu-ewm <gnu.ewm@protonmail.com>, 2021. +# gnu-ewm <gnu.ewm@protonmail.com>, 2021, 2023. # vrid <patryksoon@live.com>, 2021. # Suchy Talerz <kacperkubis06@gmail.com>, 2021. # Bartosz Stasiak <bs97086@amu.edu.pl>, 2021. @@ -60,22 +60,23 @@ # Mateusz ZdrzaÅ‚ek <matjozohd@gmail.com>, 2022. # Konrad <kobe-interactive@protonmail.com>, 2022. # Pixel Zone - Godot Engine Tutorials <karoltomaszewskimusic@gmail.com>, 2022. -# DK0492 <doriankaczmarek28@gmail.com>, 2022. +# DK0492 <doriankaczmarek28@gmail.com>, 2022, 2023. # Dawid Skubij <davidsd@tlen.pl>, 2022. -# kingofsponges <q.patex.q@gmail.com>, 2022. +# kingofsponges <q.patex.q@gmail.com>, 2022, 2023. # Patryk Morawski <gormit7@gmail.com>, 2022. # Adrians <adrianspl@o2.pl>, 2022. # Wodorek <Krol.w94@gmail.com>, 2022. # Filip GliszczyÅ„ski <filipgliszczynski@gmail.com>, 2022. # Piotr Åšlusarz <piotrekslusarz@outlook.com>, 2022. # Jan Kurzak <Iqaz0oki@outlook.com>, 2022. +# Wojciech Pluta <wojciech.pluta@oracle.com>, 2022. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-12-12 09:46+0000\n" -"Last-Translator: Tomek <kobewi4e@gmail.com>\n" +"PO-Revision-Date: 2023-01-20 10:19+0000\n" +"Last-Translator: RM <synaptykq@gmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/" "godot/pl/>\n" "Language: pl\n" @@ -84,7 +85,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -104,7 +105,7 @@ msgstr "Kod zakoÅ„czenia" #: core/bind/core_bind.cpp msgid "V-Sync Enabled" -msgstr "V-Sync WÅ‚Ä…czone" +msgstr "V-Sync wÅ‚Ä…czone" #: core/bind/core_bind.cpp main/main.cpp msgid "V-Sync Via Compositor" @@ -112,7 +113,7 @@ msgstr "V-Sync przez kompozytor" #: core/bind/core_bind.cpp main/main.cpp msgid "Delta Smoothing" -msgstr "WygÅ‚adzanie Delta" +msgstr "WygÅ‚adzanie delta" #: core/bind/core_bind.cpp msgid "Low Processor Usage Mode" @@ -5523,18 +5524,16 @@ msgid "Show Line Numbers" msgstr "Pokaż numery linii" #: editor/editor_settings.cpp -#, fuzzy msgid "Line Numbers Zero Padded" -msgstr "Numer linii:" +msgstr "Numery linii wyrównane zerami" #: editor/editor_settings.cpp msgid "Show Bookmark Gutter" msgstr "Pokaż ciek zakÅ‚adek" #: editor/editor_settings.cpp -#, fuzzy msgid "Show Breakpoint Gutter" -msgstr "PomiÅ„ punkty wstrzymania" +msgstr "Pokaż rynnÄ™ punktów wstrzymania" #: editor/editor_settings.cpp msgid "Show Info Gutter" @@ -5561,9 +5560,8 @@ msgid "Line Length Guideline Hard Column" msgstr "Wytyczne dotyczÄ…ce dÅ‚ugoÅ›ci linii twardej kolumny" #: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Script List" -msgstr "Edytor skryptów" +msgstr "Lista skryptów" #: editor/editor_settings.cpp msgid "Show Members Overview" @@ -5594,9 +5592,8 @@ msgid "Auto Reload Scripts On External Change" msgstr "Automatycznie przeÅ‚aduj skrypty przy zmianie zewnÄ™trznej" #: editor/editor_settings.cpp -#, fuzzy msgid "Create Signal Callbacks" -msgstr "Opóźnienia wymuszania shaderów" +msgstr "Twórz wywoÅ‚ania zwrotne sygnałów" #: editor/editor_settings.cpp msgid "Sort Members Outline Alphabetically" @@ -5623,9 +5620,8 @@ msgid "Caret Blink Speed" msgstr "PrÄ™dkość migania karety" #: editor/editor_settings.cpp -#, fuzzy msgid "Right Click Moves Caret" -msgstr "Prawy klik, aby dodać punkt" +msgstr "Prawy klik przesuwa kursor" #: editor/editor_settings.cpp modules/gdscript/gdscript.cpp #: modules/gdscript/gdscript_editor.cpp @@ -5647,56 +5643,51 @@ msgstr "Opóźnienie zakoÅ„czenia kodu" #: editor/editor_settings.cpp msgid "Put Callhint Tooltip Below Current Line" -msgstr "" +msgstr "Ustaw dymek podpowiedzi pod aktualnym wierszem" #: editor/editor_settings.cpp msgid "Callhint Tooltip Offset" -msgstr "" +msgstr "PrzesuniÄ™cie dymka podpowiedzi" #: editor/editor_settings.cpp -#, fuzzy msgid "Complete File Paths" -msgstr "Skopiuj Å›cieżkÄ™ wÄ™zÅ‚a" +msgstr "UzupeÅ‚niaj Å›cieżki plików" #: editor/editor_settings.cpp modules/gdscript/gdscript_editor.cpp -#, fuzzy msgid "Add Type Hints" -msgstr "Dodaj typ" +msgstr "Dodaj wskazówki typów" #: editor/editor_settings.cpp msgid "Use Single Quotes" msgstr "Użyj pojedynczych cudzysÅ‚owów" #: editor/editor_settings.cpp -#, fuzzy msgid "Show Help Index" -msgstr "Pokaż linie pomocnicze" +msgstr "Pokaż indeks pomocy" #: editor/editor_settings.cpp msgid "Help Font Size" -msgstr "" +msgstr "Rozmiar czcionki pomocy" #: editor/editor_settings.cpp msgid "Help Source Font Size" -msgstr "" +msgstr "Rozmiar czcionki kodu w pomocy" #: editor/editor_settings.cpp msgid "Help Title Font Size" -msgstr "" +msgstr "Rozmiar czcionki tytuÅ‚u w pomocy" #: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp msgid "Grid Map" msgstr "Siatka" #: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp -#, fuzzy msgid "Pick Distance" -msgstr "Wybierz odlegÅ‚ość:" +msgstr "Dystans Å‚apania" #: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Preview Size" -msgstr "PodglÄ…d" +msgstr "Rozmiar podglÄ…du" #: editor/editor_settings.cpp msgid "Primary Grid Color" @@ -5707,32 +5698,27 @@ msgid "Secondary Grid Color" msgstr "Pomocniczy kolor siatki" #: editor/editor_settings.cpp -#, fuzzy msgid "Selection Box Color" -msgstr "Tylko zaznaczenie" +msgstr "Kolor prostopadÅ‚oÅ›cianu zaznaczenia" #: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp -#, fuzzy msgid "3D Gizmos" -msgstr "Uchwyty" +msgstr "Uchwyty 3D" #: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp #: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp -#, fuzzy msgid "Gizmo Colors" -msgstr "Kolory emisji" +msgstr "Kolory uchwytów" #: editor/editor_settings.cpp -#, fuzzy msgid "Instanced" -msgstr "Instancja" +msgstr "Instancjonowany" #: editor/editor_settings.cpp modules/gltf/gltf_node.cpp #: scene/3d/physics_body.cpp -#, fuzzy msgid "Joint" -msgstr "Punkt" +msgstr "ZÅ‚Ä…cze" #: editor/editor_settings.cpp scene/2d/collision_shape_2d.cpp #: scene/2d/cpu_particles_2d.cpp scene/2d/touch_screen_button.cpp @@ -5744,276 +5730,236 @@ msgid "Shape" msgstr "KsztaÅ‚t" #: editor/editor_settings.cpp -#, fuzzy msgid "Primary Grid Steps" -msgstr "Krok siatki:" +msgstr "Główne kroki siatki" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid Size" -msgstr "Krok siatki:" +msgstr "Rozmiar siatki" #: editor/editor_settings.cpp msgid "Grid Division Level Max" -msgstr "" +msgstr "Maksymalny poziom podziaÅ‚u siatki" #: editor/editor_settings.cpp msgid "Grid Division Level Min" -msgstr "" +msgstr "Minimalny poziom podziaÅ‚u siatki" #: editor/editor_settings.cpp msgid "Grid Division Level Bias" -msgstr "" +msgstr "Tendencja poziomu podziaÅ‚u siatki" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid XZ Plane" -msgstr "Malowanie GridMap" +msgstr "PÅ‚aszczyzna siatki XZ" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid XY Plane" -msgstr "Malowanie GridMap" +msgstr "PÅ‚aszczyzna siatki XY" #: editor/editor_settings.cpp -#, fuzzy msgid "Grid YZ Plane" -msgstr "Malowanie GridMap" +msgstr "PÅ‚aszczyzna siatki YZ" #: editor/editor_settings.cpp -#, fuzzy msgid "Default FOV" -msgstr "DomyÅ›lny" +msgstr "DomyÅ›lne pole widzenia (FOV)" #: editor/editor_settings.cpp -#, fuzzy msgid "Default Z Near" -msgstr "DomyÅ›lny motyw" +msgstr "DomyÅ›lne bliskie Z" #: editor/editor_settings.cpp -#, fuzzy msgid "Default Z Far" -msgstr "DomyÅ›lny" +msgstr "DomyÅ›lne dalekie Z" #: editor/editor_settings.cpp msgid "Lightmap Baking Number Of CPU Threads" -msgstr "" +msgstr "Liczba wÄ…tków CPU dla wypalania map Å›wiatÅ‚a" #: editor/editor_settings.cpp -#, fuzzy msgid "Navigation Scheme" -msgstr "Tryb nawigacji" +msgstr "Schemat nawigacji" #: editor/editor_settings.cpp -#, fuzzy msgid "Invert Y Axis" -msgstr "Edytuj oÅ› Y" +msgstr "Odwróć oÅ› Y" #: editor/editor_settings.cpp -#, fuzzy msgid "Invert X Axis" -msgstr "Edytuj oÅ› X" +msgstr "Odwróć oÅ› X" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Style" -msgstr "Oddal" +msgstr "Styl przybliżenia" #: editor/editor_settings.cpp -#, fuzzy msgid "Emulate Numpad" -msgstr "WÅ‚Ä…cz emulacjÄ™ klawiatury numerycznej" +msgstr "Emuluj klawiaturÄ™ numerycznÄ…" #: editor/editor_settings.cpp -#, fuzzy msgid "Emulate 3 Button Mouse" -msgstr "WÅ‚Ä…cz emulacjÄ™ Å›rodkowego przycisku myszy" +msgstr "Emuluj trzyprzyciskowÄ… mysz" #: editor/editor_settings.cpp -#, fuzzy msgid "Orbit Modifier" -msgstr "Pierwsze zmodyfikowane" +msgstr "Modyfikator orbity" #: editor/editor_settings.cpp -#, fuzzy msgid "Pan Modifier" -msgstr "Tryb przesuwania" +msgstr "Modyfikator przesuwania" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Modifier" -msgstr "Zmodyfikowany" +msgstr "Modyfikator przybliżenia" #: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Warped Mouse Panning" -msgstr "" +msgstr "ZawiniÄ™te przesuwanie myszÄ…" #: editor/editor_settings.cpp -#, fuzzy msgid "Navigation Feel" -msgstr "Tryb nawigacji" +msgstr "Preferencje nawigacji" #: editor/editor_settings.cpp msgid "Orbit Sensitivity" -msgstr "" +msgstr "CzuÅ‚ość orbity" #: editor/editor_settings.cpp msgid "Orbit Inertia" -msgstr "" +msgstr "BezwÅ‚adność orbity" #: editor/editor_settings.cpp -#, fuzzy msgid "Translation Inertia" -msgstr "TÅ‚umaczenia" +msgstr "BezwÅ‚adność przesuniÄ™cia" #: editor/editor_settings.cpp -#, fuzzy msgid "Zoom Inertia" -msgstr "Przybliż" +msgstr "BezwÅ‚adność przybliżenia" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook" -msgstr "\"Wolny widok\" w górÄ™" +msgstr "Wolny widok" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Navigation Scheme" -msgstr "Utwórz siatkÄ™ nawigacyjnÄ… (Navigation Mesh)" +msgstr "Schemat nawigacji wolnego widoku" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Sensitivity" -msgstr "\"Wolny widok\" w lewo" +msgstr "CzuÅ‚ość wolnego widoku" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Inertia" -msgstr "\"Wolny widok\" w lewo" +msgstr "BezwÅ‚adność wolnego widoku" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Base Speed" -msgstr "Modyfikator prÄ™dkoÅ›ci swobodnego widoku" +msgstr "Bazowa prÄ™dkość wolnego widoku" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Activation Modifier" -msgstr "Wolny modyfikator swobodnego widoku" +msgstr "Modyfikator aktywacji wolnego widoku" #: editor/editor_settings.cpp -#, fuzzy msgid "Freelook Speed Zoom Link" -msgstr "Modyfikator prÄ™dkoÅ›ci swobodnego widoku" +msgstr "Szybkość swobodnego widoku zależna od przybliżenia" #: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Grid Color" -msgstr "Wybierz Kolor" +msgstr "Kolor siatki" #: editor/editor_settings.cpp -#, fuzzy msgid "Guides Color" -msgstr "Wybierz Kolor" +msgstr "Kolor prowadnic" #: editor/editor_settings.cpp -#, fuzzy msgid "Smart Snapping Line Color" -msgstr "Inteligentne przyciÄ…ganie" +msgstr "Kolor linii inteligentnego przyciÄ…gania" #: editor/editor_settings.cpp msgid "Bone Width" -msgstr "" +msgstr "Szerokość koÅ›ci" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Color 1" -msgstr "ZmieÅ„ nazwÄ™ elementu koloru" +msgstr "Kolor koÅ›ci 1" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Color 2" -msgstr "ZmieÅ„ nazwÄ™ elementu koloru" +msgstr "Kolor koÅ›ci 2" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Selected Color" -msgstr "Konfiguruj wybrany profil:" +msgstr "Kolor zaznaczenia koÅ›ci" #: editor/editor_settings.cpp msgid "Bone IK Color" -msgstr "" +msgstr "Kolor koÅ›ci IK" #: editor/editor_settings.cpp msgid "Bone Outline Color" -msgstr "" +msgstr "Kolor obrysu koÅ›ci" #: editor/editor_settings.cpp -#, fuzzy msgid "Bone Outline Size" -msgstr "Rozmiar zarysu:" +msgstr "Rozmiar obrysu koÅ›ci" #: editor/editor_settings.cpp msgid "Viewport Border Color" -msgstr "" +msgstr "Kolor obwódki viewportu" #: editor/editor_settings.cpp msgid "Constrain Editor View" -msgstr "" +msgstr "Ogranicz widok edytora" #: editor/editor_settings.cpp msgid "Simple Panning" -msgstr "" +msgstr "Proste przesuwanie" #: editor/editor_settings.cpp msgid "Scroll To Pan" -msgstr "" +msgstr "Przewijanie przesuwa" #: editor/editor_settings.cpp -#, fuzzy msgid "Pan Speed" -msgstr "Szybkość:" +msgstr "Szybkość przesuwania" #: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Poly Editor" -msgstr "WielokÄ…t 2D UV Edytor" +msgstr "Edytor wielokÄ…tów" #: editor/editor_settings.cpp msgid "Point Grab Radius" -msgstr "" +msgstr "PromieÅ„ chwytania punktów" #: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Show Previous Outline" -msgstr "Poprzednia pÅ‚aszczyzna" +msgstr "Pokaż poprzedni obrys" #: editor/editor_settings.cpp editor/scene_tree_dock.cpp -#, fuzzy msgid "Autorename Animation Tracks" -msgstr "ZmieÅ„ nazwÄ™ animacji" +msgstr "Automatycznie przemianuj Å›cieżki animacji" #: editor/editor_settings.cpp msgid "Default Create Bezier Tracks" -msgstr "" +msgstr "Twórz domyÅ›lnie Å›cieżki Beziera" #: editor/editor_settings.cpp -#, fuzzy msgid "Default Create Reset Tracks" -msgstr "Utwórz Å›cieżki RESET" +msgstr "DomyÅ›lnie twórz Å›cieżki resetu" #: editor/editor_settings.cpp msgid "Onion Layers Past Color" -msgstr "" +msgstr "PrzeszÅ‚y kolor warstw cebuli" #: editor/editor_settings.cpp msgid "Onion Layers Future Color" -msgstr "" +msgstr "PrzyszÅ‚y kolor warstw cebuli" #: editor/editor_settings.cpp -#, fuzzy msgid "Visual Editors" -msgstr "Edytor grup" +msgstr "Edytory wizualne" #: editor/editor_settings.cpp msgid "Minimap Opacity" @@ -6021,69 +5967,61 @@ msgstr "Przezroczystość minimapy" #: editor/editor_settings.cpp msgid "Window Placement" -msgstr "" +msgstr "Ustawienie okna" #: editor/editor_settings.cpp scene/2d/back_buffer_copy.cpp scene/2d/sprite.cpp #: scene/2d/visibility_notifier_2d.cpp scene/3d/sprite_3d.cpp #: scene/gui/control.cpp -#, fuzzy msgid "Rect" -msgstr "CaÅ‚y obszar" +msgstr "ProstokÄ…t" #: editor/editor_settings.cpp -#, fuzzy msgid "Rect Custom Position" -msgstr "Ustaw punkt kontrolny wychodzÄ…cy z krzywej" +msgstr "WÅ‚asna pozycja prostokÄ…ta" #: editor/editor_settings.cpp platform/android/export/export_plugin.cpp msgid "Screen" -msgstr "" +msgstr "Ekran" #: editor/editor_settings.cpp -#, fuzzy msgid "Auto Save" -msgstr "Tnij automatycznie" +msgstr "Autozapis" #: editor/editor_settings.cpp -#, fuzzy msgid "Save Before Running" -msgstr "Zapisz scenÄ™ przed uruchomieniem..." +msgstr "Zapisz przed uruchomieniem" #: editor/editor_settings.cpp -#, fuzzy msgid "Font Size" -msgstr "Widok z przodu" +msgstr "Rozmiar czcionki" #: editor/editor_settings.cpp #: modules/gdscript/language_server/gdscript_language_server.cpp -#, fuzzy msgid "Remote Host" -msgstr "Zdalny " +msgstr "Zdalny host" #: editor/editor_settings.cpp #: modules/gdscript/language_server/gdscript_language_server.cpp -#, fuzzy msgid "Remote Port" -msgstr "UsuÅ„ punkt" +msgstr "Zdalny port" #: editor/editor_settings.cpp -#, fuzzy msgid "Editor SSL Certificates" -msgstr "Ustawienia edytora" +msgstr "Certyfikaty SSL edytora" #: editor/editor_settings.cpp msgid "HTTP Proxy" -msgstr "" +msgstr "Proxy HTTP" #: editor/editor_settings.cpp msgid "Host" -msgstr "" +msgstr "Host" #: editor/editor_settings.cpp editor/fileserver/editor_file_server.cpp #: main/main.cpp modules/mono/mono_gd/gd_mono.cpp #: scene/resources/default_theme/default_theme.cpp msgid "Port" -msgstr "" +msgstr "Port" #. TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects. #: editor/editor_settings.cpp @@ -6092,171 +6030,150 @@ msgstr "Menedżer projektów" #. TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects. #: editor/editor_settings.cpp -#, fuzzy msgid "Sorting Order" -msgstr "w kolejnoÅ›ci:" +msgstr "Kolejność sortowania" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Symbol Color" -msgstr "" +msgstr "Kolor symbolu" #: editor/editor_settings.cpp msgid "Keyword Color" -msgstr "" +msgstr "Kolor sÅ‚owa kluczowego" #: editor/editor_settings.cpp msgid "Control Flow Keyword Color" -msgstr "" +msgstr "Kolor sÅ‚owa kluczowego kontroli przepÅ‚ywu" #: editor/editor_settings.cpp -#, fuzzy msgid "Base Type Color" -msgstr "ZmieÅ„ typ podstawowy" +msgstr "Kolor typu bazowego" #: editor/editor_settings.cpp msgid "Engine Type Color" -msgstr "" +msgstr "Kolor typu silnika" #: editor/editor_settings.cpp msgid "User Type Color" -msgstr "" +msgstr "Kolor typu użytkownika" #: editor/editor_settings.cpp msgid "Comment Color" -msgstr "" +msgstr "Kolor komentarza" #: editor/editor_settings.cpp -#, fuzzy msgid "String Color" -msgstr "Zapisywanie pliku:" +msgstr "Kolor ciÄ…gu znaków" #: editor/editor_settings.cpp platform/javascript/export/export.cpp #: platform/uwp/export/export.cpp #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Background Color" -msgstr "Kolor tÅ‚a nieprawidÅ‚owy." +msgstr "Kolor tÅ‚a" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Background Color" -msgstr "Kolor tÅ‚a nieprawidÅ‚owy." +msgstr "Kolor tÅ‚a uzupeÅ‚niania" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Completion Selected Color" -msgstr "Importuj zaznaczone" +msgstr "Kolor zaznaczenia uzupeÅ‚niania" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Completion Existing Color" -msgstr "" +msgstr "Kolor istniejÄ…cego uzupeÅ‚niania" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Completion Scroll Color" -msgstr "" +msgstr "Kolor przewijania uzupeÅ‚niania" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Completion Font Color" -msgstr "" +msgstr "Kolor czcionki uzupeÅ‚niania" #: editor/editor_settings.cpp -#, fuzzy msgid "Text Color" -msgstr "NastÄ™pny poziom" +msgstr "Kolor tekstu" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Line Number Color" -msgstr "Numer linii:" +msgstr "Kolor numerów linii" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Safe Line Number Color" -msgstr "Numer linii:" +msgstr "Kolor numerów bezpiecznych linii" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Caret Color" -msgstr "" +msgstr "Kolor kursora" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Caret Background Color" -msgstr "Kolor tÅ‚a nieprawidÅ‚owy." +msgstr "Kolor tÅ‚a kursora" #: editor/editor_settings.cpp -#, fuzzy msgid "Text Selected Color" -msgstr "UsuÅ„ zaznaczone" +msgstr "Kolor zaznaczonego tekstu" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Selection Color" -msgstr "Tylko zaznaczenie" +msgstr "Kolor zaznaczenia" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Brace Mismatch Color" -msgstr "" +msgstr "Kolor niedopasowanych nawiasów" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Current Line Color" -msgstr "Aktualna scena" +msgstr "Kolor aktualnej linii" #: editor/editor_settings.cpp msgid "Line Length Guideline Color" -msgstr "" +msgstr "Kolor prowadnicy dÅ‚ugoÅ›ci linii" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Word Highlighted Color" -msgstr "PodÅ›wietlacz skÅ‚adni" +msgstr "Kolor podÅ›wietlonego sÅ‚owa" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Number Color" -msgstr "" +msgstr "Kolor numeru" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Function Color" -msgstr "Funkcja" +msgstr "Kolor funkcji" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Member Variable Color" -msgstr "ZmieÅ„ nawÄ™ zmiennej" +msgstr "Kolor zmiennej czÅ‚onkowskiej" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Mark Color" -msgstr "Wybierz Kolor" +msgstr "Kolor oznaczenia" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Bookmark Color" -msgstr "ZakÅ‚adki" +msgstr "Kolor zakÅ‚adki" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Breakpoint Color" -msgstr "Punkty wstrzymania" +msgstr "Kolor punktu wstrzymania" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Executing Line Color" -msgstr "" +msgstr "Kolor wywoÅ‚ywanej linii" #: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp msgid "Code Folding Color" -msgstr "" +msgstr "Kolor zawiniÄ™cia kodu" #: editor/editor_settings.cpp -#, fuzzy msgid "Search Result Color" -msgstr "Wyniki wyszukiwania" +msgstr "Kolor wyniku wyszukiwania" #: editor/editor_settings.cpp -#, fuzzy msgid "Search Result Border Color" -msgstr "Wyniki wyszukiwania" +msgstr "Kolor obramowania wyniku wyszukiwania" #: editor/editor_spin_slider.cpp msgid "Hold %s to round to integers. Hold Shift for more precise changes." @@ -6265,14 +6182,12 @@ msgstr "" "bardziej precyzyjnych zmian." #: editor/editor_spin_slider.cpp scene/gui/button.cpp -#, fuzzy msgid "Flat" -msgstr "PÅ‚askie 0" +msgstr "PÅ‚aski" #: editor/editor_spin_slider.cpp -#, fuzzy msgid "Hide Slider" -msgstr "Tryb kolizji" +msgstr "Ukryj suwak" #: editor/editor_sub_scene.cpp msgid "Select Node(s) to Import" @@ -6563,7 +6478,7 @@ msgstr "" #: editor/fileserver/editor_file_server.cpp msgid "File Server" -msgstr "" +msgstr "Serwer plików" #: editor/fileserver/editor_file_server.cpp #: editor/plugins/version_control_editor_plugin.cpp @@ -6936,43 +6851,40 @@ msgstr "ZarzÄ…dzaj grupami" #: editor/import/editor_import_collada.cpp msgid "Collada" -msgstr "" +msgstr "Collada" #: editor/import/editor_import_collada.cpp msgid "Use Ambient" -msgstr "" +msgstr "Użyj otoczenia" #: editor/import/resource_importer_bitmask.cpp -#, fuzzy msgid "Create From" -msgstr "Utwórz katalog" +msgstr "Utwórz z" #: editor/import/resource_importer_bitmask.cpp #: servers/audio/effects/audio_effect_compressor.cpp msgid "Threshold" -msgstr "" +msgstr "Próg" #: editor/import/resource_importer_csv_translation.cpp #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_scene.cpp #: editor/import/resource_importer_texture.cpp #: editor/import/resource_importer_wav.cpp scene/3d/gi_probe.cpp -#, fuzzy msgid "Compress" -msgstr "Komponenty" +msgstr "Skompresuj" #: editor/import/resource_importer_csv_translation.cpp msgid "Delimiter" -msgstr "" +msgstr "Separator" #: editor/import/resource_importer_layered_texture.cpp -#, fuzzy msgid "ColorCorrect" -msgstr "Funkcja koloru." +msgstr "ColorCorrect" #: editor/import/resource_importer_layered_texture.cpp msgid "No BPTC If RGB" -msgstr "" +msgstr "Bez BPTC jeÅ›li RGB" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp scene/2d/cpu_particles_2d.cpp @@ -6980,31 +6892,29 @@ msgstr "" #: scene/resources/material.cpp scene/resources/particles_material.cpp #: scene/resources/texture.cpp scene/resources/visual_shader.cpp msgid "Flags" -msgstr "" +msgstr "Flagi" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp scene/animation/tween.cpp #: scene/resources/texture.cpp msgid "Repeat" -msgstr "" +msgstr "Powtórz" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp scene/2d/light_2d.cpp #: scene/gui/control.cpp -#, fuzzy msgid "Filter" -msgstr "Filtry:" +msgstr "Filtr" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Mipmaps" -msgstr "SygnaÅ‚y" +msgstr "Mipmapy" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp msgid "Anisotropic" -msgstr "" +msgstr "Anizotropowe" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp @@ -7012,51 +6922,43 @@ msgid "sRGB" msgstr "sRGB" #: editor/import/resource_importer_layered_texture.cpp -#, fuzzy msgid "Slices" -msgstr "Tnij automatycznie" +msgstr "KawaÅ‚ki" #: editor/import/resource_importer_layered_texture.cpp #: scene/gui/aspect_ratio_container.cpp scene/gui/control.cpp #: scene/gui/nine_patch_rect.cpp scene/gui/scroll_container.cpp #: scene/resources/style_box.cpp -#, fuzzy msgid "Horizontal" -msgstr "Poziomo:" +msgstr "Poziomo" #: editor/import/resource_importer_layered_texture.cpp #: scene/gui/aspect_ratio_container.cpp scene/gui/control.cpp #: scene/gui/nine_patch_rect.cpp scene/gui/scroll_container.cpp #: scene/resources/style_box.cpp -#, fuzzy msgid "Vertical" -msgstr "Pionowo:" +msgstr "Pionowo" #: editor/import/resource_importer_obj.cpp -#, fuzzy msgid "Generate Tangents" -msgstr "Wygeneruj punkty" +msgstr "Wygeneruj styczne" #: editor/import/resource_importer_obj.cpp -#, fuzzy msgid "Scale Mesh" -msgstr "Tryb skalowania" +msgstr "Skaluj siatkÄ™" #: editor/import/resource_importer_obj.cpp -#, fuzzy msgid "Offset Mesh" -msgstr "PrzesuniÄ™cie:" +msgstr "PrzesuÅ„ siatkÄ™" #: editor/import/resource_importer_obj.cpp #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Octahedral Compression" -msgstr "Kompresja" +msgstr "Kompresja oÅ›mioÅ›cienna" #: editor/import/resource_importer_obj.cpp -#, fuzzy msgid "Optimize Mesh Flags" -msgstr "Rozmiar: " +msgstr "Optymalizuj flagi siatki" #: editor/import/resource_importer_scene.cpp msgid "Import as Single Scene" @@ -7100,101 +7002,84 @@ msgstr "Importuj jako wiele scen + materiaÅ‚y" #: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp #: scene/3d/physics_joint.cpp -#, fuzzy msgid "Nodes" -msgstr "WÄ™zeÅ‚" +msgstr "WÄ™zÅ‚y" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Root Type" -msgstr "Wróć" +msgstr "Typ korzenia" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Root Name" -msgstr "Nazwa zdalnego repozytorium" +msgstr "Nazwa korzenia" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Root Scale" -msgstr "Skaluj" +msgstr "Skala korzenia" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Custom Script" -msgstr "NiestandardowyWÄ™zeÅ‚" +msgstr "WÅ‚asny skrypt" #: editor/import/resource_importer_scene.cpp scene/resources/texture.cpp -#, fuzzy msgid "Storage" -msgstr "Zapisywanie pliku:" +msgstr "Przechowywanie" #: editor/import/resource_importer_scene.cpp msgid "Use Legacy Names" -msgstr "" +msgstr "Użyj starszych nazw" #: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp -#, fuzzy msgid "Materials" -msgstr "Zmiany materiaÅ‚u:" +msgstr "MateriaÅ‚y" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Keep On Reimport" -msgstr "Importuj ponownie" +msgstr "Zachowaj po reimporcie" #: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp -#, fuzzy msgid "Meshes" -msgstr "Siatka" +msgstr "Siatki" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Ensure Tangents" -msgstr "Modyfikuj stycznÄ… krzywej" +msgstr "Zapewnij styczne" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Light Baking" -msgstr "Lightmapping" +msgstr "Wypalanie Å›wiatÅ‚a" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Lightmap Texel Size" -msgstr "Stwórz Lightmaps" +msgstr "Rozmiar teksela mapy Å›wiatÅ‚a" #: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp msgid "Skins" -msgstr "" +msgstr "Skórki" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Use Named Skins" -msgstr "Użyj przyciÄ…gania skali" +msgstr "Używaj nazwanych skórek" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "External Files" -msgstr "Otwórz plik" +msgstr "Pliki zewnÄ™trzne" #: editor/import/resource_importer_scene.cpp msgid "Store In Subdir" -msgstr "" +msgstr "Przechowaj w podfolderze" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Filter Script" -msgstr "Filtruj skrypty" +msgstr "Skrypt filtra" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Keep Custom Tracks" -msgstr "PrzeksztaÅ‚canie" +msgstr "Zachowaj wÅ‚asne Å›cieżki" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Optimizer" -msgstr "Zoptymalizuj" +msgstr "Optymalizator" #: editor/import/resource_importer_scene.cpp #: editor/plugins/item_list_editor_plugin.cpp main/main.cpp @@ -7208,41 +7093,34 @@ msgstr "Zoptymalizuj" #: scene/3d/sprite_3d.cpp scene/gui/graph_edit.cpp #: scene/gui/rich_text_label.cpp scene/resources/curve.cpp #: scene/resources/environment.cpp scene/resources/material.cpp -#, fuzzy msgid "Enabled" -msgstr "WÅ‚Ä…cz" +msgstr "WÅ‚Ä…czony" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Max Linear Error" -msgstr "Maks. bÅ‚Ä…d liniowy:" +msgstr "Maks. bÅ‚Ä…d liniowy" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Max Angular Error" -msgstr "Maks. bÅ‚Ä…d kÄ…towy:" +msgstr "Maks. bÅ‚Ä…d kÄ…towy" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Max Angle" -msgstr "Wartość" +msgstr "Maksymalny kÄ…t" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Remove Unused Tracks" -msgstr "UsuÅ„ Å›cieżkÄ™ animacji" +msgstr "UsuÅ„ nieużywane Å›cieżki" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Clips" -msgstr "Klipy animacji" +msgstr "Klipy" #: editor/import/resource_importer_scene.cpp scene/2d/cpu_particles_2d.cpp #: scene/2d/particles_2d.cpp scene/3d/area.cpp scene/3d/cpu_particles.cpp #: scene/3d/particles.cpp scene/resources/environment.cpp -#, fuzzy msgid "Amount" -msgstr "IloÅ›c:" +msgstr "Ilość" #: editor/import/resource_importer_scene.cpp #: editor/plugins/mesh_library_editor_plugin.cpp @@ -7258,9 +7136,8 @@ msgid "Generating Lightmaps" msgstr "Generowanie Lightmapy" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Generating for Mesh:" -msgstr "Generowanie dla siatki: " +msgstr "Generowanie dla siatki:" #: editor/import/resource_importer_scene.cpp msgid "Running Custom Script..." @@ -7293,34 +7170,37 @@ msgid "" "%s: Texture detected as used as a normal map in 3D. Enabling red-green " "texture compression to reduce memory usage (blue channel is discarded)." msgstr "" +"%s: Tekstura wykryta jako mapa normalnych w 3D. WÅ‚Ä…czam czerwono-zielonÄ… " +"kompresjÄ™ tekstury, by zmniejszyć zużycie pamiÄ™ci (niebieski kanaÅ‚ jest " +"odrzucony)." #: editor/import/resource_importer_texture.cpp msgid "" "%s: Texture detected as used in 3D. Enabling filter, repeat, mipmap " "generation and VRAM texture compression." msgstr "" +"%s: Tekstura wykryta jako używana w 3D. WÅ‚Ä…czam filtrowanie, powtarzanie, " +"generacjÄ™ mipmap i kompresjÄ™ tekstur VRAM." #: editor/import/resource_importer_texture.cpp msgid "2D, Detect 3D" -msgstr "" +msgstr "2D, wykryj 3D" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "2D Pixel" -msgstr "Widoczne piksele" +msgstr "2D piksel" #: editor/import/resource_importer_texture.cpp scene/resources/texture.cpp msgid "Lossy Quality" -msgstr "" +msgstr "Stratna jakość" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "HDR Mode" -msgstr "Tryb zaznaczenia" +msgstr "Tryb HDR" #: editor/import/resource_importer_texture.cpp msgid "BPTC LDR" -msgstr "" +msgstr "LDR BPTC" #: editor/import/resource_importer_texture.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/2d/cpu_particles_2d.cpp @@ -7330,105 +7210,94 @@ msgid "Normal Map" msgstr "Mapa normalnych" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Process" -msgstr "Przetwarzanie koÅ„cowe" +msgstr "Przetwarzanie" #: editor/import/resource_importer_texture.cpp msgid "Fix Alpha Border" -msgstr "" +msgstr "Popraw obramowanie alfa" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Premult Alpha" -msgstr "Edytuj wielokÄ…t" +msgstr "WstÄ™pnie przemnóż alfÄ™" #: editor/import/resource_importer_texture.cpp msgid "Hdr As Srgb" -msgstr "" +msgstr "HDR jako sRGB" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Invert Color" -msgstr "WierzchoÅ‚ki" +msgstr "Odwróć kolor" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Normal Map Invert Y" -msgstr "Losowa skala:" +msgstr "Odwróć Y mapy normalnych" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Size Limit" -msgstr "Limity" +msgstr "Limit rozmiaru" #: editor/import/resource_importer_texture.cpp msgid "Detect 3D" -msgstr "" +msgstr "Wykryj 3D" #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "SVG" -msgstr "HSV" +msgstr "SVG" #: editor/import/resource_importer_texture.cpp msgid "" "Warning, no suitable PC VRAM compression enabled in Project Settings. This " "texture will not display correctly on PC." msgstr "" +"Ostrzeżenie, brak ustawionej w ustawieniach projektu odpowiedniej kompresji " +"PC VRAM. Ta tekstura nie bÄ™dzie siÄ™ poprawnie wyÅ›wietlać na PC." #: editor/import/resource_importer_texture_atlas.cpp -#, fuzzy msgid "Atlas File" -msgstr "Rozmiar zarysu:" +msgstr "Plik atlasu" #: editor/import/resource_importer_texture_atlas.cpp -#, fuzzy msgid "Import Mode" -msgstr "Tryb eksportu:" +msgstr "Tryb importu" #: editor/import/resource_importer_texture_atlas.cpp -#, fuzzy msgid "Crop To Region" -msgstr "Ustaw obszar Kafelka" +msgstr "Przytnij do regionu" #: editor/import/resource_importer_texture_atlas.cpp msgid "Trim Alpha Border From Region" -msgstr "" +msgstr "Przytnij obramowanie alfy z regionu" #: editor/import/resource_importer_wav.cpp scene/2d/physics_body_2d.cpp -#, fuzzy msgid "Force" -msgstr "Wrzuć na siÅ‚Ä™" +msgstr "SiÅ‚a" #: editor/import/resource_importer_wav.cpp msgid "8 Bit" -msgstr "" +msgstr "8 bitów" #: editor/import/resource_importer_wav.cpp main/main.cpp #: modules/mono/editor/csharp_project.cpp modules/mono/godotsharp_dirs.cpp #: modules/mono/mono_gd/gd_mono.cpp msgid "Mono" -msgstr "" +msgstr "Mono" #: editor/import/resource_importer_wav.cpp -#, fuzzy msgid "Max Rate" -msgstr "WÄ™zeÅ‚ Mieszania" +msgstr "Maksymalne tempo" #: editor/import/resource_importer_wav.cpp -#, fuzzy msgid "Max Rate Hz" -msgstr "WÄ™zeÅ‚ Mieszania" +msgstr "Maksymalne tempo Hz" #: editor/import/resource_importer_wav.cpp msgid "Trim" -msgstr "" +msgstr "Przytnij" #: editor/import/resource_importer_wav.cpp -#, fuzzy msgid "Normalize" -msgstr "Format" +msgstr "Normalizuj" #: editor/import/resource_importer_wav.cpp #: scene/resources/audio_stream_sample.cpp @@ -7437,15 +7306,13 @@ msgstr "Tryb zapÄ™tlenia" #: editor/import/resource_importer_wav.cpp #: scene/resources/audio_stream_sample.cpp -#, fuzzy msgid "Loop Begin" -msgstr "Tryb przesuwania" +msgstr "PoczÄ…tek pÄ™tli" #: editor/import/resource_importer_wav.cpp #: scene/resources/audio_stream_sample.cpp -#, fuzzy msgid "Loop End" -msgstr "Tryb przesuwania" +msgstr "Koniec pÄ™tli" #: editor/import_defaults_editor.cpp msgid "Select Importer" @@ -7523,27 +7390,24 @@ msgid "Failed to load resource." msgstr "Nie udaÅ‚o siÄ™ wczytać zasobu." #: editor/inspector_dock.cpp -#, fuzzy msgid "Property Name Style" -msgstr "Nazwa projektu:" +msgstr "Styl nazw wÅ‚aÅ›ciwoÅ›ci" #: editor/inspector_dock.cpp scene/gui/color_picker.cpp msgid "Raw" msgstr "Raw" #: editor/inspector_dock.cpp -#, fuzzy msgid "Capitalized" -msgstr "Wielkie litery na poczÄ…tku słów" +msgstr "Z wielkiej litery" #: editor/inspector_dock.cpp -#, fuzzy msgid "Localized" -msgstr "Ustawienia regionalne" +msgstr "TÅ‚umaczone" #: editor/inspector_dock.cpp msgid "Localization not available for current language." -msgstr "" +msgstr "TÅ‚umaczenie niedostÄ™pne dla aktualnego jÄ™zyka." #: editor/inspector_dock.cpp msgid "Copy Properties" @@ -8088,9 +7952,8 @@ msgid "New" msgstr "Nowy" #: editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy msgid "Paste As Reference" -msgstr "Referencja klasy %s" +msgstr "Wklej jako referencjÄ™" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Edit Transitions..." @@ -8281,9 +8144,8 @@ msgid "Set the end animation. This is useful for sub-transitions." msgstr "Ustaw koniec animacji. To jest przydatne dla podprzejść." #: editor/plugins/animation_state_machine_editor.cpp -#, fuzzy msgid "Transition:" -msgstr "PrzejÅ›cie: " +msgstr "PrzejÅ›cie:" #: editor/plugins/animation_state_machine_editor.cpp msgid "Play Mode:" @@ -8420,7 +8282,7 @@ msgstr "Filtry..." #: editor/plugins/asset_library_editor_plugin.cpp scene/main/http_request.cpp msgid "Use Threads" -msgstr "" +msgstr "Używaj wÄ…tków" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Contents:" @@ -8548,9 +8410,8 @@ msgid "Download Error" msgstr "BÅ‚Ä…d pobierania" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Available URLs" -msgstr "DostÄ™pne profile:" +msgstr "DostÄ™pne URL" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Download for this asset is already in progress!" @@ -8585,25 +8446,21 @@ msgid "Loading..." msgstr "Wczytywanie..." #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgctxt "Pagination" msgid "First" msgstr "PoczÄ…tek" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgctxt "Pagination" msgid "Previous" msgstr "Wstecz" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgctxt "Pagination" msgid "Next" msgstr "Dalej" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgctxt "Pagination" msgid "Last" msgstr "Koniec" @@ -8654,7 +8511,7 @@ msgstr "Testowanie" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Failed to get repository configuration." -msgstr "" +msgstr "Nie udaÅ‚o siÄ™ uzyskać konfiguracji repozytorium." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Assets ZIP File" @@ -8713,7 +8570,7 @@ msgstr "Stwórz Lightmaps" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "LightMap Bake" -msgstr "" +msgstr "Wypal mapÄ™ Å›wiatÅ‚a" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Select lightmap bake file:" @@ -9220,23 +9077,20 @@ msgid "View" msgstr "Widok" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Show" -msgstr "Pokaż siatkÄ™" +msgstr "Pokaż" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Show When Snapping" -msgstr "Inteligentne przyciÄ…ganie" +msgstr "Pokaż podczas przyciÄ…gania" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Hide" -msgstr "" +msgstr "Ukryj" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Toggle Grid" -msgstr "PrzeÅ‚Ä…cz tryb" +msgstr "PrzeÅ‚Ä…cz siatkÄ™" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/polygon_2d_editor_plugin.cpp @@ -9588,16 +9442,15 @@ msgstr "Gradient edytowany" #: editor/plugins/gradient_texture_2d_editor_plugin.cpp msgid "Swap GradientTexture2D Fill Points" -msgstr "" +msgstr "ZamieÅ„ punkty wypeÅ‚nienia GradientTexture2D" #: editor/plugins/gradient_texture_2d_editor_plugin.cpp msgid "Swap Gradient Fill Points" -msgstr "" +msgstr "ZamieÅ„ punkty wypeÅ‚nienia gradientu" #: editor/plugins/gradient_texture_2d_editor_plugin.cpp -#, fuzzy msgid "Toggle Grid Snap" -msgstr "PrzeÅ‚Ä…cz tryb" +msgstr "PrzeÅ‚Ä…cz przyciÄ…ganie do siatki" #: editor/plugins/item_list_editor_plugin.cpp editor/project_export.cpp #: scene/3d/label_3d.cpp scene/gui/button.cpp scene/gui/dialogs.cpp @@ -9616,13 +9469,12 @@ msgstr "Ikona" #: editor/plugins/item_list_editor_plugin.cpp msgid "ID" -msgstr "" +msgstr "ID" #: editor/plugins/item_list_editor_plugin.cpp #: scene/resources/default_theme/default_theme.cpp -#, fuzzy msgid "Separator" -msgstr "Separacja:" +msgstr "Separator" #: editor/plugins/item_list_editor_plugin.cpp msgid "Item %d" @@ -9859,9 +9711,8 @@ msgstr "" "%s" #: editor/plugins/mesh_library_editor_plugin.cpp -#, fuzzy msgid "MeshLibrary" -msgstr "Biblioteka meshów" +msgstr "Biblioteka siatek" #: editor/plugins/mesh_library_editor_plugin.cpp msgid "Add Item" @@ -9884,14 +9735,12 @@ msgid "Update from Scene" msgstr "Aktualizuj ze sceny" #: editor/plugins/mesh_library_editor_plugin.cpp -#, fuzzy msgid "Apply without Transforms" -msgstr "Zastosuj transformacje MeshInstance" +msgstr "Zastosuj bez transformacji" #: editor/plugins/mesh_library_editor_plugin.cpp -#, fuzzy msgid "Apply with Transforms" -msgstr "Zastosuj transformacje MeshInstance" +msgstr "Zastosuj z transformacjami" #: editor/plugins/multimesh_editor_plugin.cpp msgid "No mesh source specified (and no MultiMesh set in node)." @@ -10059,9 +9908,8 @@ msgid "Volume" msgstr "GÅ‚oÅ›ność" #: editor/plugins/particles_editor_plugin.cpp -#, fuzzy msgid "Emission Source:" -msgstr "ŹródÅ‚a emisji: " +msgstr "ŹródÅ‚o emisji:" #: editor/plugins/particles_editor_plugin.cpp msgid "A processor material of type 'ParticlesMaterial' is required." @@ -10417,7 +10265,7 @@ msgstr "Synchronizuj koÅ›ci z wielokÄ…tem" #: editor/plugins/ray_cast_2d_editor_plugin.cpp msgid "Set cast_to" -msgstr "" +msgstr "Ustaw cast_to" #: editor/plugins/resource_preloader_editor_plugin.cpp msgid "ERROR: Couldn't load resource!" @@ -10748,58 +10596,51 @@ msgstr "Wyniki wyszukiwania" #: editor/plugins/script_editor_plugin.cpp msgid "Open Dominant Script On Scene Change" -msgstr "" +msgstr "Otwórz dominujÄ…cy skrypt przy zmianie sceny" #: editor/plugins/script_editor_plugin.cpp msgid "External" -msgstr "" +msgstr "ZewnÄ™trzne" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Use External Editor" -msgstr "Debugowanie z zewnÄ™trznym edytorem" +msgstr "Użyj zewnÄ™trznego edytora" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Exec Path" -msgstr "Åšcieżka eksportu" +msgstr "Åšcieżka uruchomienia" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Script Temperature Enabled" -msgstr "Wybierz plik szablonu" +msgstr "WÅ‚Ä…cz temperaturÄ™ skryptów" #: editor/plugins/script_editor_plugin.cpp msgid "Highlight Current Script" -msgstr "" +msgstr "PodÅ›wietl aktualny skrypt" #: editor/plugins/script_editor_plugin.cpp msgid "Script Temperature History Size" -msgstr "" +msgstr "Rozmiar historii temperatury skryptów" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Current Script Background Color" -msgstr "Kolor tÅ‚a nieprawidÅ‚owy." +msgstr "Kolor tÅ‚a aktualnego skryptu" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Group Help Pages" -msgstr "Grupuj wybrane" +msgstr "Grupuj strony pomocy" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Sort Scripts By" -msgstr "Utwórz Skrypt" +msgstr "Sortuj skrypty po" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "List Script Names As" -msgstr "Nazwa skryptu:" +msgstr "Listuj nazwy skryptów jako" #: editor/plugins/script_editor_plugin.cpp msgid "Exec Flags" -msgstr "" +msgstr "Parametry uruchomienia" #: editor/plugins/script_editor_plugin.cpp msgid "Clear Recent Scripts" @@ -11118,7 +10959,7 @@ msgstr "TyÅ‚ perspektywicznie" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portale aktywne]" @@ -11160,15 +11001,13 @@ msgstr "PrzesuÅ„" #. TRANSLATORS: Refers to changing the scale of a node in the 3D editor. #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Scaling:" -msgstr "Skalowanie: " +msgstr "Skalowanie:" #. TRANSLATORS: Refers to changing the position of a node in the 3D editor. #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Translating:" -msgstr "Przesuwanie: " +msgstr "Przesuwanie:" #: editor/plugins/spatial_editor_plugin.cpp msgid "Rotating %s degrees." @@ -11316,13 +11155,14 @@ msgstr "PodglÄ…d kinowy" #: editor/plugins/spatial_editor_plugin.cpp msgid "(Not in GLES2)" -msgstr "" +msgstr "(Nie w GLES2)" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "" "Debug draw modes are only available when using the GLES3 renderer, not GLES2." -msgstr "NiedostÄ™pne dla renderera GLES2." +msgstr "" +"Tryby rysowania debugowego sÄ… dostÄ™pne tylko w przypadku korzystania z " +"renderera GLES3, a nie GLES2." #: editor/plugins/spatial_editor_plugin.cpp msgid "Freelook Left" @@ -11617,16 +11457,15 @@ msgstr "Po" #: editor/plugins/spatial_editor_plugin.cpp msgid "Manipulator Gizmo Size" -msgstr "" +msgstr "Regulacja wielkoÅ›ci uchwytu" #: editor/plugins/spatial_editor_plugin.cpp msgid "Manipulator Gizmo Opacity" -msgstr "" +msgstr "Regulacja przezroczystoÅ›ci uchwytu" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Show Viewport Rotation Gizmo" -msgstr "Zablokuj obrót widoku" +msgstr "Pokaż obrót widoku uchwytu" #: editor/plugins/spatial_editor_plugin.cpp msgid "Unnamed Gizmo" @@ -11678,9 +11517,8 @@ msgid "Invalid geometry, can't replace by mesh." msgstr "NieprawidÅ‚owa geometria, nie można zastÄ…pić przez siatkÄ™." #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Convert to MeshInstance2D" -msgstr "ZamieÅ„ na Mesh2D" +msgstr "Konwertuj do MeshInstance2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Invalid geometry, can't create polygon." @@ -11711,19 +11549,16 @@ msgid "Sprite" msgstr "Sprite" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Simplification:" -msgstr "Uproszczenie: " +msgstr "Uproszczenie:" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Shrink (Pixels):" -msgstr "Zmniejsz (piksele): " +msgstr "Zmniejsz (piksele):" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Grow (Pixels):" -msgstr "ZwiÄ™ksz (piksele): " +msgstr "ZwiÄ™ksz (piksele):" #: editor/plugins/sprite_editor_plugin.cpp msgid "Update Preview" @@ -11786,9 +11621,8 @@ msgid "New Animation" msgstr "Nowa animacja" #: editor/plugins/sprite_frames_editor_plugin.cpp -#, fuzzy msgid "Filter animations" -msgstr "Filtruj metody" +msgstr "Filtruj animacje" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Speed:" @@ -12088,9 +11922,8 @@ msgstr "" "Zamknąć tak czy inaczej?" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Remove Type" -msgstr "UsuÅ„ Kafelek" +msgstr "UsuÅ„ typ" #: editor/plugins/theme_editor_plugin.cpp msgid "" @@ -16481,7 +16314,7 @@ msgstr "" #: main/main.cpp msgid "Verbose stdout" -msgstr "" +msgstr "Werbalne stdout" #: main/main.cpp scene/main/scene_tree.cpp scene/resources/multimesh.cpp #, fuzzy @@ -16500,11 +16333,11 @@ msgstr "PowiÄ™ksz do zaznaczenia" #: main/main.cpp msgid "Low Processor Mode" -msgstr "" +msgstr "Tryb niskiego wykorzystania procesora" #: main/main.cpp msgid "Delta Sync After Draw" -msgstr "" +msgstr "Synchronizacja delta po wyÅ›wietlaniu" #: main/main.cpp msgid "iOS" @@ -16512,7 +16345,7 @@ msgstr "iOS" #: main/main.cpp msgid "Hide Home Indicator" -msgstr "" +msgstr "Ukryj wskaźnik powitalny" #: main/main.cpp #, fuzzy @@ -16526,11 +16359,11 @@ msgstr "Punkt" #: main/main.cpp msgid "Touch Delay" -msgstr "" +msgstr "Opóźnienie dotyku" #: main/main.cpp servers/visual_server.cpp msgid "GLES3" -msgstr "" +msgstr "GLES3" #: main/main.cpp servers/visual_server.cpp #, fuzzy @@ -16555,43 +16388,39 @@ msgstr "" #: main/main.cpp msgid "Boot Splash" -msgstr "" +msgstr "Ekran uruchamiania" #: main/main.cpp -#, fuzzy msgid "Show Image" -msgstr "Pokaż koÅ›ci" +msgstr "Pokaż obraz" #: main/main.cpp msgid "Image" -msgstr "" +msgstr "Obraz" #: main/main.cpp msgid "Fullsize" -msgstr "" +msgstr "PeÅ‚ny rozmiar" #: main/main.cpp scene/resources/dynamic_font.cpp -#, fuzzy msgid "Use Filter" -msgstr "Filtr:" +msgstr "Użyj filtra" #: main/main.cpp scene/resources/style_box.cpp -#, fuzzy msgid "BG Color" -msgstr "Kolory" +msgstr "Kolor tÅ‚a" #: main/main.cpp -#, fuzzy msgid "macOS Native Icon" -msgstr "Ustaw ikonÄ™ Kafelka" +msgstr "Ikona natywna macOS" #: main/main.cpp msgid "Windows Native Icon" -msgstr "" +msgstr "Ikona natywna Windows" #: main/main.cpp msgid "Buffering" -msgstr "" +msgstr "Buforowanie" #: main/main.cpp msgid "Agile Event Flushing" @@ -16599,30 +16428,27 @@ msgstr "" #: main/main.cpp msgid "Emulate Touch From Mouse" -msgstr "" +msgstr "Emulacja dotyku za pomocÄ… myszy" #: main/main.cpp msgid "Emulate Mouse From Touch" -msgstr "" +msgstr "Emulacja myszy za pomocÄ… dotyku" #: main/main.cpp -#, fuzzy msgid "Mouse Cursor" -msgstr "Przycisk myszy" +msgstr "Kursor myszy" #: main/main.cpp -#, fuzzy msgid "Custom Image" -msgstr "NiestandardowyWÄ™zeÅ‚" +msgstr "Niestandardowy obraz" #: main/main.cpp msgid "Custom Image Hotspot" -msgstr "" +msgstr "WÅ‚asny punkt dostÄ™pu do obrazów" #: main/main.cpp -#, fuzzy msgid "Tooltip Position Offset" -msgstr "Offset obrotu:" +msgstr "PrzesuniÄ™cie pozycji podpowiedzi" #: main/main.cpp modules/mono/mono_gd/gd_mono.cpp #, fuzzy @@ -16630,22 +16456,20 @@ msgid "Debugger Agent" msgstr "Debugger" #: main/main.cpp modules/mono/mono_gd/gd_mono.cpp -#, fuzzy msgid "Wait For Debugger" -msgstr "Debugger" +msgstr "Czekanie na Debuggera" #: main/main.cpp modules/mono/mono_gd/gd_mono.cpp -#, fuzzy msgid "Wait Timeout" -msgstr "Przekroczenie czasu." +msgstr "Limit czasu oczekiwania" #: main/main.cpp msgid "Runtime" -msgstr "" +msgstr "Åšrodowisko pracy" #: main/main.cpp msgid "Unhandled Exception Policy" -msgstr "" +msgstr "Polityka dotyczÄ…ca wyjÄ…tków nieobsÅ‚ugiwanych" #: main/main.cpp #, fuzzy @@ -16654,22 +16478,20 @@ msgstr "Znajdź typ wÄ™zÅ‚a" #: main/main.cpp scene/gui/texture_progress.cpp #: scene/gui/viewport_container.cpp -#, fuzzy msgid "Stretch" -msgstr "ZaÅ‚aduj" +msgstr "RozciÄ…gnij" #: main/main.cpp -#, fuzzy msgid "Aspect" -msgstr "Inspektor" +msgstr "Aspekt" #: main/main.cpp msgid "Shrink" -msgstr "" +msgstr "Zmniejsz" #: main/main.cpp scene/main/scene_tree.cpp msgid "Auto Accept Quit" -msgstr "" +msgstr "Automatyczne akceptowanie zamkniÄ™cia" #: main/main.cpp scene/main/scene_tree.cpp #, fuzzy @@ -16677,25 +16499,24 @@ msgid "Quit On Go Back" msgstr "Wróć" #: main/main.cpp scene/main/viewport.cpp -#, fuzzy msgid "Snap Controls To Pixels" -msgstr "PrzyciÄ…gaj do boków wÄ™zÅ‚a" +msgstr "Przymocuj elementy sterujÄ…ce do pikseli" #: main/main.cpp msgid "Dynamic Fonts" -msgstr "" +msgstr "Czcionki dynamiczne" #: main/main.cpp msgid "Use Oversampling" -msgstr "" +msgstr "Zastosuj nadpróbkowanie" #: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp msgid "Active Soft World" -msgstr "" +msgstr "Aktywuj wsparcie SoftBody World" #: modules/csg/csg_gizmos.cpp msgid "CSG" -msgstr "" +msgstr "CSG" #: modules/csg/csg_gizmos.cpp msgid "Change Cylinder Radius" @@ -16714,30 +16535,26 @@ msgid "Change Torus Outer Radius" msgstr "ZmieÅ„ zewnÄ™trzny promieÅ„Â torusa" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Operation" -msgstr "Opcje" +msgstr "Operacja" #: modules/csg/csg_shape.cpp msgid "Calculate Tangents" -msgstr "" +msgstr "Oblicz styczne" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Use Collision" -msgstr "Kolizja" +msgstr "Użyj kolizji" #: modules/csg/csg_shape.cpp servers/physics_2d_server.cpp -#, fuzzy msgid "Collision Layer" -msgstr "Tryb kolizji" +msgstr "Warstwa kolizji" #: modules/csg/csg_shape.cpp scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp #: scene/3d/ray_cast.cpp scene/3d/spring_arm.cpp #: scene/resources/navigation_mesh.cpp servers/physics_server.cpp -#, fuzzy msgid "Collision Mask" -msgstr "Tryb kolizji" +msgstr "Maska kolizji" #: modules/csg/csg_shape.cpp #, fuzzy @@ -16752,9 +16569,8 @@ msgstr "ZmieÅ„Â wielkość liter" #: scene/resources/cylinder_shape.cpp scene/resources/environment.cpp #: scene/resources/navigation_mesh.cpp scene/resources/primitive_meshes.cpp #: scene/resources/sphere_shape.cpp -#, fuzzy msgid "Radius" -msgstr "PromieÅ„:" +msgstr "PromieÅ„" #: modules/csg/csg_shape.cpp scene/resources/primitive_meshes.cpp #, fuzzy @@ -16762,33 +16578,28 @@ msgid "Radial Segments" msgstr "Argumenty głównej sceny:" #: modules/csg/csg_shape.cpp scene/resources/primitive_meshes.cpp -#, fuzzy msgid "Rings" -msgstr "Ostrzeżenia" +msgstr "PierÅ›cienie" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Smooth Faces" -msgstr "PÅ‚ynny Krok" +msgstr "GÅ‚adkie twarze" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Sides" -msgstr "Pokaż prowadnice" +msgstr "Boki" #: modules/csg/csg_shape.cpp msgid "Cone" -msgstr "" +msgstr "Stożek" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Inner Radius" -msgstr "ZmieÅ„ wewnÄ™trzny promieÅ„ torusa" +msgstr "PromieÅ„ wewnÄ™trzny" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Outer Radius" -msgstr "ZmieÅ„ zewnÄ™trzny promieÅ„Â torusa" +msgstr "promieÅ„ zewnÄ™trzny" #: modules/csg/csg_shape.cpp msgid "Ring Sides" @@ -16797,7 +16608,6 @@ msgstr "" #: modules/csg/csg_shape.cpp scene/2d/collision_polygon_2d.cpp #: scene/2d/light_occluder_2d.cpp scene/2d/polygon_2d.cpp #: scene/3d/collision_polygon.cpp -#, fuzzy msgid "Polygon" msgstr "WielokÄ…t" @@ -16810,9 +16620,8 @@ msgid "Spin Sides" msgstr "" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Path Node" -msgstr "Wklej wÄ™zÅ‚y" +msgstr "Åšcieżka wÄ™zÅ‚a" #: modules/csg/csg_shape.cpp #, fuzzy @@ -16821,21 +16630,19 @@ msgstr "Utwórz wewnÄ™trzny wierzchoÅ‚ek" #: modules/csg/csg_shape.cpp msgid "Path Interval" -msgstr "" +msgstr "OdstÄ™p miÄ™dzy Å›cieżkami" #: modules/csg/csg_shape.cpp msgid "Path Simplify Angle" msgstr "" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Path Rotation" -msgstr "Obrót losowy:" +msgstr "Obrót Å›cieżki" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Path Local" -msgstr "UczyÅ„ lokalnym" +msgstr "Åšcieżka lokalna" #: modules/csg/csg_shape.cpp #, fuzzy @@ -17046,7 +16853,7 @@ msgstr "Nie bazuje na pliku zasobów" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary format (missing @path)" -msgstr "Niepoprawna instancja formatu sÅ‚ownika (brakujÄ…cy @path)" +msgstr "Niepoprawna instancja formatu sÅ‚ownika (brakuje @path)" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary format (can't load script at @path)" @@ -17059,7 +16866,7 @@ msgstr "Niepoprawna instancja formatu sÅ‚ownika (niepoprawny skrypt w @path)" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary (invalid subclasses)" -msgstr "Niepoprawna instancja sÅ‚ownika (niepoprawne podklasy)" +msgstr "Niepoprawny sÅ‚ownik instancji (niepoprawne podklasy)" #: modules/gdscript/gdscript_functions.cpp msgid "Object can't provide a length." @@ -17288,27 +17095,27 @@ msgstr "PrzesuÅ„ zÅ‚Ä…cze" #: modules/gltf/gltf_skin.cpp msgid "Joint I To Bone I" -msgstr "" +msgstr "Staw I do koÅ›ci I" #: modules/gltf/gltf_skin.cpp msgid "Joint I To Name" -msgstr "" +msgstr "Staw I do nazwy" #: modules/gltf/gltf_skin.cpp msgid "Godot Skin" -msgstr "" +msgstr "Skórka Godot" #: modules/gltf/gltf_spec_gloss.cpp msgid "Diffuse Img" -msgstr "" +msgstr "Rozmycie obrazu" #: modules/gltf/gltf_spec_gloss.cpp msgid "Diffuse Factor" -msgstr "" +msgstr "Współczynnik rozmycia" #: modules/gltf/gltf_spec_gloss.cpp msgid "Gloss Factor" -msgstr "" +msgstr "Współczynnik poÅ‚ysku" #: modules/gltf/gltf_spec_gloss.cpp #, fuzzy @@ -17391,19 +17198,16 @@ msgid "Skeletons" msgstr "Szkielet" #: modules/gltf/gltf_state.cpp -#, fuzzy msgid "Skeleton To Node" -msgstr "Wybierz wÄ™zeÅ‚" +msgstr "Szkielet do wÄ™zÅ‚a" #: modules/gltf/gltf_state.cpp -#, fuzzy msgid "Animations" -msgstr "Animacje:" +msgstr "Animacje" #: modules/gltf/gltf_texture.cpp -#, fuzzy msgid "Src Image" -msgstr "Pokaż koÅ›ci" +msgstr "Obraz źródÅ‚owy" #: modules/gridmap/grid_map.cpp msgid "Mesh Library" @@ -17421,33 +17225,29 @@ msgstr "Stwórz Lightmaps" #: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp msgid "Cell" -msgstr "" +msgstr "Komórka" #: modules/gridmap/grid_map.cpp -#, fuzzy msgid "Octant Size" -msgstr "Widok z przodu" +msgstr "Wielkość oktantu" #: modules/gridmap/grid_map.cpp -#, fuzzy msgid "Center X" -msgstr "WyÅ›rodkowane" +msgstr "WyÅ›rodkowanie X" #: modules/gridmap/grid_map.cpp -#, fuzzy msgid "Center Y" -msgstr "WyÅ›rodkowane" +msgstr "WyÅ›rodkowanie Y" #: modules/gridmap/grid_map.cpp -#, fuzzy msgid "Center Z" -msgstr "WyÅ›rodkowane" +msgstr "WyÅ›rodkowanie Z" #: modules/gridmap/grid_map.cpp scene/2d/collision_object_2d.cpp #: scene/2d/tile_map.cpp scene/3d/collision_object.cpp scene/3d/soft_body.cpp #: scene/resources/material.cpp msgid "Mask" -msgstr "" +msgstr "Maska" #: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp #, fuzzy @@ -17458,9 +17258,8 @@ msgstr "Nawigacja" #: scene/2d/navigation_agent_2d.cpp scene/2d/navigation_polygon.cpp #: scene/2d/tile_map.cpp scene/3d/navigation.cpp scene/3d/navigation_agent.cpp #: scene/3d/navigation_mesh_instance.cpp -#, fuzzy msgid "Navigation Layers" -msgstr "Tryb nawigacji" +msgstr "Warstwy nawigacji" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Next Plane" @@ -17620,9 +17419,8 @@ msgid "Plotting lightmaps" msgstr "KreÅ›lenie map Å›wiatÅ‚a" #: modules/lightmapper_cpu/register_types.cpp -#, fuzzy msgid "CPU Lightmapper" -msgstr "Stwórz Lightmaps" +msgstr "Mapper Å›wiatÅ‚a CPU" #: modules/lightmapper_cpu/register_types.cpp msgid "Low Quality Ray Count" @@ -17644,22 +17442,20 @@ msgstr "" #: modules/minimp3/resource_importer_mp3.cpp #: modules/stb_vorbis/audio_stream_ogg_vorbis.cpp #: modules/stb_vorbis/resource_importer_ogg_vorbis.cpp -#, fuzzy msgid "Loop Offset" -msgstr "PrzesuniÄ™cie:" +msgstr "PrzesuniÄ™cie pÄ™tli" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "Eye Height" -msgstr "" +msgstr "Wysokość oczu" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "IOD" -msgstr "" +msgstr "IOD" #: modules/mobile_vr/mobile_vr_interface.cpp -#, fuzzy msgid "Display Width" -msgstr "Widok siatki" +msgstr "Szerokość wyÅ›wietlacza" #: modules/mobile_vr/mobile_vr_interface.cpp #, fuzzy @@ -17668,15 +17464,15 @@ msgstr "Widok bezcieniowy" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "Oversample" -msgstr "" +msgstr "Nadpróbkowanie" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "K1" -msgstr "" +msgstr "K1" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "K2" -msgstr "" +msgstr "K2" #: modules/mono/csharp_script.cpp msgid "Class name can't be a reserved keyword" @@ -17687,14 +17483,12 @@ msgid "Build Solution" msgstr "Zbuduj rozwiÄ…zanie" #: modules/mono/editor/csharp_project.cpp -#, fuzzy msgid "Auto Update Project" -msgstr "Projekt bez nazwy" +msgstr "Automatyczna aktualizacja projektu" #: modules/mono/godotsharp_dirs.cpp -#, fuzzy msgid "Assembly Name" -msgstr "Pokaż wszystko" +msgstr "Nazwa zespoÅ‚u" #: modules/mono/godotsharp_dirs.cpp #, fuzzy @@ -17702,9 +17496,8 @@ msgid "Solution Directory" msgstr "Wybierz katalog" #: modules/mono/godotsharp_dirs.cpp -#, fuzzy msgid "C# Project Directory" -msgstr "Wybierz katalog" +msgstr "Katalog projektów C#" #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" @@ -17775,42 +17568,39 @@ msgstr "Parsowanie Geometrii..." #: modules/navigation/navigation_mesh_generator.cpp msgid "Done!" -msgstr "SkoÅ„czone!" +msgstr "Gotowe!" #: modules/opensimplex/noise_texture.cpp msgid "Seamless" msgstr "" #: modules/opensimplex/noise_texture.cpp -#, fuzzy msgid "As Normal Map" -msgstr "Losowa skala:" +msgstr "Jako normalna mapa" #: modules/opensimplex/noise_texture.cpp msgid "Bump Strength" -msgstr "" +msgstr "SiÅ‚a uderzenia" #: modules/opensimplex/noise_texture.cpp msgid "Noise" -msgstr "" +msgstr "Szum" #: modules/opensimplex/noise_texture.cpp -#, fuzzy msgid "Noise Offset" -msgstr "Offset siatki:" +msgstr "Redukcja szumów" #: modules/opensimplex/open_simplex_noise.cpp msgid "Octaves" -msgstr "" +msgstr "Oktawy" #: modules/opensimplex/open_simplex_noise.cpp msgid "Period" -msgstr "" +msgstr "Okres" #: modules/opensimplex/open_simplex_noise.cpp -#, fuzzy msgid "Persistence" -msgstr "Perspektywa" +msgstr "TrwaÅ‚ość" #: modules/opensimplex/open_simplex_noise.cpp msgid "Lacunarity" @@ -17821,14 +17611,12 @@ msgid "Subject" msgstr "" #: modules/regex/regex.cpp -#, fuzzy msgid "Names" -msgstr "Nazwa" +msgstr "Nazwy" #: modules/regex/regex.cpp -#, fuzzy msgid "Strings" -msgstr "Ustawienia:" +msgstr "CiÄ…gi tekstowe" #: modules/upnp/upnp.cpp msgid "Discover Multicast If" @@ -17901,7 +17689,9 @@ msgstr "WÄ™zeÅ‚ zwróciÅ‚ niewÅ‚aÅ›ciwÄ… sekwencjÄ™ wyjÅ›ciowÄ…: " #: modules/visual_script/visual_script.cpp msgid "Found sequence bit but not the node in the stack, report bug!" -msgstr "Znaleziono bit sekwencji, ale nie wÄ™zeÅ‚ na stosie, zgÅ‚oÅ› bÅ‚Ä…d!" +msgstr "" +"Nie znaleziono wÄ™zÅ‚a w stosie, choć znaleziono ciÄ…g bitów. Powiadom o " +"bÅ‚Ä™dzie!" #: modules/visual_script/visual_script.cpp #, fuzzy @@ -18031,7 +17821,7 @@ msgstr "Wklej wÄ™zeÅ‚ VisualScript" #: modules/visual_script/visual_script_editor.cpp msgid "Remove VisualScript Nodes" -msgstr "Usuwanie wÄ™złów VisualScript" +msgstr "UsuÅ„ wÄ™zÅ‚y VisualScript" #: modules/visual_script/visual_script_editor.cpp msgid "Duplicate VisualScript Nodes" @@ -18088,7 +17878,7 @@ msgstr "" #: modules/visual_script/visual_script_editor.cpp msgid "Add Getter Property" -msgstr "Dodaj wÅ‚aÅ›ciwość Gettera" +msgstr "Dodaj wÅ‚aÅ›ciwość Getter" #: modules/visual_script/visual_script_editor.cpp msgid "Add Setter Property" @@ -19165,14 +18955,12 @@ msgid "Code Signing" msgstr "DMG podpisywania kodu" #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "" "'apksigner' could not be found. Please check that the command is available " "in the Android SDK build-tools directory. The resulting %s is unsigned." msgstr "" -"\"apksigner\" nie zostaÅ‚ znaleziony.\n" -"Sprawdź, czy komenda jest dostÄ™pna w folderze narzÄ™dzi SDK Androida.\n" -"Wynikowy %s jest niepodpisany." +"\"apksigner\" nie zostaÅ‚ znaleziony. Sprawdź, czy komenda jest dostÄ™pna w " +"folderze narzÄ™dzi SDK Androida. Wynikowy %s jest niepodpisany." #: platform/android/export/export_plugin.cpp msgid "Signing debug %s..." @@ -19233,15 +19021,12 @@ msgstr "" "informacja o wersji. Zainstaluj ponownie z menu \"Projekt\"." #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "" "Android build version mismatch: Template installed: %s, Godot version: %s. " "Please reinstall Android build template from 'Project' menu." msgstr "" -"Niezgodna wersja buildu Androida:\n" -" Zainstalowany szablon: %s\n" -" Wersja Godota: %s\n" -"Zainstaluj ponownie szablon z menu \"Projekt\"." +"Niezgodna wersja buildu Androida: Zainstalowany szablon: %s Wersja Godota: " +"%s. Zainstaluj ponownie szablon z menu \"Projekt\"." #: platform/android/export/export_plugin.cpp #, fuzzy @@ -19264,13 +19049,12 @@ msgid "Building Android Project (gradle)" msgstr "Budowanie projektu Androida (gradle)" #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "" "Building of Android project failed, check output for the error. " "Alternatively visit docs.godotengine.org for Android build documentation." msgstr "" -"Budowanie projektu Androida siÄ™ nie powiodÅ‚o, sprawdź wyjÅ›cie bÅ‚Ä™du.\n" -"Alternatywnie, odwiedź docs.godotengine.org po dokumentacjÄ™ budowania dla " +"Budowanie projektu Androida siÄ™ nie powiodÅ‚o, sprawdź dane wyjÅ›ciowe bÅ‚Ä™du. " +"Ewentualnie, odwiedź docs.godotengine.org po dokumentacjÄ™ budowania dla " "Androida." #: platform/android/export/export_plugin.cpp @@ -19295,20 +19079,16 @@ msgid "Creating APK..." msgstr "Tworzenie APK..." #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "Could not find template APK to export: \"%s\"." -msgstr "" -"Nie udaÅ‚o siÄ™ znaleźć szablonu APK do eksportu:\n" -"%s" +msgstr "Nie udaÅ‚o siÄ™ znaleźć szablonu APK do eksportu: \"%s\"." #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "" "Missing libraries in the export template for the selected architectures: %s. " "Please build a template with all required libraries, or uncheck the missing " "architectures in the export preset." msgstr "" -"BrakujÄ…ce biblioteki w szablonie eksportu dla wybranej architektury: %s.\n" +"BrakujÄ…ce biblioteki w szablonie eksportu dla wybranej architektury: %s. " "Zbuduj szablon ze wszystkimi wymaganymi bibliotekami lub odznacz brakujÄ…ce " "architektury w profilu eksportu." @@ -21873,8 +21653,8 @@ msgid "" "A material to process the particles is not assigned, so no behavior is " "imprinted." msgstr "" -"Nie przypisano materiaÅ‚u do przetwarzania czÄ…steczek, wiÄ™c zmiany nie bÄ™dÄ… " -"widoczne." +"MateriaÅ‚ nie jest przypisany do czÄ…steczek, wiÄ™c ich zachowanie bÄ™dzie " +"niewidoczne." #: scene/2d/particles_2d.cpp msgid "" @@ -22041,9 +21821,8 @@ msgid "Safe Margin" msgstr "Ustaw margines" #: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp -#, fuzzy msgid "Sync To Physics" -msgstr " (fizyczny)" +msgstr "Synchronizuj z fizykÄ…" #: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp #, fuzzy @@ -23067,7 +22846,8 @@ msgstr "" msgid "" "Nothing is visible because meshes have not been assigned to draw passes." msgstr "" -"Nic nie jest widoczne, bo siatki nie zostaÅ‚y przypisane do kolejki rysowania." +"Nic nie jest widoczne ponieważ siatki nie zostaÅ‚y przydzielone do przebiegów " +"wyÅ›wietlajÄ…cych." #: scene/3d/particles.cpp msgid "" @@ -26857,7 +26637,7 @@ msgstr "Debug kanaÅ‚u UV" #: scene/resources/environment.cpp msgid "Blur" -msgstr "" +msgstr "Rozmazanie" #: scene/resources/environment.cpp msgid "Edge Sharpness" @@ -27983,9 +27763,8 @@ msgstr "" #: servers/audio/effects/audio_effect_delay.cpp #: servers/audio/effects/audio_effect_phaser.cpp #: servers/audio/effects/audio_effect_reverb.cpp -#, fuzzy msgid "Feedback" -msgstr "OceÅ„ dokumentacjÄ™" +msgstr "Informacja zwrotna" #: servers/audio/effects/audio_effect_delay.cpp #, fuzzy @@ -27994,7 +27773,7 @@ msgstr "OmiÅ„" #: servers/audio/effects/audio_effect_distortion.cpp msgid "Pre Gain" -msgstr "" +msgstr "WstÄ™pne wzmocnienie" #: servers/audio/effects/audio_effect_distortion.cpp msgid "Keep Hf Hz" @@ -28010,17 +27789,16 @@ msgid "Post Gain" msgstr "Po" #: servers/audio/effects/audio_effect_filter.cpp -#, fuzzy msgid "Resonance" -msgstr "Zasoby" +msgstr "Rezonans" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Ceiling dB" -msgstr "" +msgstr "Sufit dB" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Threshold dB" -msgstr "" +msgstr "Wartość progowa dB" #: servers/audio/effects/audio_effect_limiter.cpp msgid "Soft Clip dB" @@ -28462,13 +28240,12 @@ msgid "Legacy Stream" msgstr "" #: servers/visual_server.cpp -#, fuzzy msgid "Batching" -msgstr "Wyszukiwanie..." +msgstr "Tworzenie pakietów wsadowych" #: servers/visual_server.cpp msgid "Use Batching" -msgstr "" +msgstr "Użyj przetwarzania wsadowego" #: servers/visual_server.cpp #, fuzzy @@ -28581,9 +28358,8 @@ msgid "Max Active Polygons" msgstr "PrzesuÅ„ WielokÄ…t" #: servers/visual_server.cpp -#, fuzzy msgid "Shader Compilation Mode" -msgstr "Sposób interpolacji" +msgstr "Sposób kompilacji shader'ów" #: servers/visual_server.cpp msgid "Max Simultaneous Compiles" diff --git a/editor/translations/pr.po b/editor/translations/pr.po index 45bbc8daf0..9b150194df 100644 --- a/editor/translations/pr.po +++ b/editor/translations/pr.po @@ -11039,7 +11039,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/pt.po b/editor/translations/pt.po index 85814ded34..0fcc083b42 100644 --- a/editor/translations/pt.po +++ b/editor/translations/pt.po @@ -13,7 +13,7 @@ # Rueben Stevens <supercell03@gmail.com>, 2017. # SARDON <fabio3_Santos@hotmail.com>, 2017. # Vinicius Gonçalves <viniciusgoncalves21@gmail.com>, 2017. -# ssantos <ssantos@web.de>, 2018, 2019, 2020, 2021, 2022. +# ssantos <ssantos@web.de>, 2018, 2019, 2020, 2021, 2022, 2023. # Gonçalo Dinis Guerreiro João <goncalojoao205@gmail.com>, 2019. # Manuela Silva <mmsrs@sky.com>, 2020. # Murilo Gama <murilovsky2030@gmail.com>, 2020, 2022. @@ -31,12 +31,13 @@ # Tuily <brizolla.tuily@gmail.com>, 2022. # Thuany <thutymsoares@gmail.com>, 2022. # Isaque Mendes <isaquemendes405@gmail.com>, 2022. +# Alex Bruno Boiniak <aboiniak@gmail.com>, 2022. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-19 08:35+0000\n" +"PO-Revision-Date: 2023-01-11 19:51+0000\n" "Last-Translator: ssantos <ssantos@web.de>\n" "Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/" "godot/pt/>\n" @@ -45,7 +46,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -183,7 +184,7 @@ msgstr "Erro" #: core/bind/core_bind.cpp msgid "Error String" -msgstr "Erro String" +msgstr "Cadeia de caracteres de erro" #: core/bind/core_bind.cpp msgid "Error Line" @@ -383,7 +384,7 @@ msgstr "Tamanho Máximo (KB)" #: core/os/input.cpp msgid "Mouse Mode" -msgstr "Modo Mouse" +msgstr "Modo do Rato" #: core/os/input.cpp msgid "Use Accumulated Input" @@ -4332,7 +4333,7 @@ msgstr "Restaurar Cenas quando carregar" #: editor/editor_node.cpp editor/editor_settings.cpp msgid "Show Thumbnail On Hover" -msgstr "Mostrar Miniatura ao Passar o Mouse Por Cima" +msgstr "Mostrar Miniatura ao Passar o Rato Por Cima" #: editor/editor_node.cpp editor/editor_settings.cpp msgid "Inspector" @@ -5479,7 +5480,7 @@ msgstr "Largura do Minimapa" #: editor/editor_settings.cpp msgid "Mouse Extra Buttons Navigate History" -msgstr "Botões extra do Mouse para Navegar no Histórico" +msgstr "Botões extra do Rato para Navegar no Histórico" #: editor/editor_settings.cpp msgid "Drag And Drop Selection" @@ -5773,7 +5774,7 @@ msgstr "Emular Teclado Numérico" #: editor/editor_settings.cpp msgid "Emulate 3 Button Mouse" -msgstr "Emular Mouse de 3 Botões" +msgstr "Emular Rato de 3 Botões" #: editor/editor_settings.cpp msgid "Orbit Modifier" @@ -5789,7 +5790,7 @@ msgstr "Modificador de Zoom" #: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Warped Mouse Panning" -msgstr "Panorama do Mouse Distorcido" +msgstr "Panorama do Rato Distorcido" #: editor/editor_settings.cpp msgid "Navigation Feel" @@ -6037,7 +6038,7 @@ msgstr "Cor do Comentário" #: editor/editor_settings.cpp msgid "String Color" -msgstr "Cor da String" +msgstr "Cor da cadeia de caracteres" #: editor/editor_settings.cpp platform/javascript/export/export.cpp #: platform/uwp/export/export.cpp @@ -6887,9 +6888,8 @@ msgstr "Filtro" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp -#, fuzzy msgid "Mipmaps" -msgstr "Sinais" +msgstr "Mipmaps" #: editor/import/resource_importer_layered_texture.cpp #: editor/import/resource_importer_texture.cpp @@ -10925,7 +10925,7 @@ msgstr "Perspetiva Traseira" msgid " [auto]" msgstr " [auto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portais ativos]" @@ -14176,17 +14176,15 @@ msgid "Invalid project path (changed anything?)." msgstr "Caminho de projeto inválido (alguma alteração?)." #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." msgstr "" -"Não consegui carregar o project.godot no caminho do projeto (erro %d). " -"Poderá estar em falta ou corrompido." +"Não pode carregar o projeto em '%s' (error %d). Pode estar sumido ou " +"corrompido." #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "Incapaz de abrir projeto em '%s'." +msgstr "Incapaz de salvar projeto em '%s' (error %d)." #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -16187,7 +16185,7 @@ msgstr "Interface Gráfica" #: main/main.cpp msgid "Drop Mouse On GUI Input Disabled" -msgstr "Desabilitar Soltar o Mouse na Entrada da Interface Gráfica" +msgstr "Desabilitar Soltar o Rato na Entrada da Interface Gráfica" #: main/main.cpp msgid "stdout" @@ -16305,15 +16303,15 @@ msgstr "Liberação Ãgil de Eventos" #: main/main.cpp msgid "Emulate Touch From Mouse" -msgstr "Emular Toque do Mouse" +msgstr "Emular Toque do Rato" #: main/main.cpp msgid "Emulate Mouse From Touch" -msgstr "Emular o Mouse do Toque" +msgstr "Emular o Rato do Toque" #: main/main.cpp msgid "Mouse Cursor" -msgstr "Cursor do Mouse" +msgstr "Cursor do Rato" #: main/main.cpp msgid "Custom Image" @@ -16516,9 +16514,8 @@ msgid "Path Local" msgstr "Caminho Local" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Path Continuous U" -msgstr "ContÃnuo" +msgstr "Caminho ContÃnuo U" #: modules/csg/csg_shape.cpp msgid "Path U Distance" @@ -16578,9 +16575,8 @@ msgstr "Carregar Apenas uma Vez" #: modules/gdnative/gdnative.cpp #: modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "Singleton" -msgstr "Esqueleto" +msgstr "Singleton" #: modules/gdnative/gdnative.cpp msgid "Symbol Prefix" @@ -17426,7 +17422,7 @@ msgstr "Nomes" #: modules/regex/regex.cpp msgid "Strings" -msgstr "Strings" +msgstr "Cadeias" #: modules/upnp/upnp.cpp msgid "Discover Multicast If" @@ -18436,9 +18432,8 @@ msgid "XR Mode" msgstr "Modo XR" #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "Hand Tracking" -msgstr "Empacotamento" +msgstr "Rastreamento das Mãos" #: platform/android/export/export_plugin.cpp msgid "Hand Tracking Frequency" @@ -18923,9 +18918,8 @@ msgid "Code Sign Identity Debug" msgstr "Depuração de Identidade de Sinal de Código" #: platform/iphone/export/export.cpp -#, fuzzy msgid "Export Method Debug" -msgstr "Exportar com Depuração" +msgstr "Exportar Método Depuração" #: platform/iphone/export/export.cpp msgid "Provisioning Profile UUID Release" @@ -19001,9 +18995,8 @@ msgid "Microphone Usage Description" msgstr "Descrição do Uso do Microfone" #: platform/iphone/export/export.cpp -#, fuzzy msgid "Photolibrary Usage Description" -msgstr "Descrições da Propriedade" +msgstr "Descrição de Uso da Fotobiblioteca" #: platform/iphone/export/export.cpp msgid "iPhone 120 X 120" @@ -19050,14 +19043,12 @@ msgid "Image Scale Mode" msgstr "Modo de Escalonamento de Imagem" #: platform/iphone/export/export.cpp -#, fuzzy msgid "Custom Image @2x" -msgstr "CustomNode" +msgstr "Personalizar Imagem @2x" #: platform/iphone/export/export.cpp -#, fuzzy msgid "Custom Image @3x" -msgstr "CustomNode" +msgstr "Personalizar Imagem @3x" #: platform/iphone/export/export.cpp msgid "Use Custom BG Color" @@ -19154,9 +19145,8 @@ msgid "Export Icon" msgstr "Exportar Ãcone" #: platform/javascript/export/export.cpp -#, fuzzy msgid "Custom HTML Shell" -msgstr "CustomNode" +msgstr "HTML Shell Personalizado" #: platform/javascript/export/export.cpp msgid "Head Include" @@ -23759,7 +23749,7 @@ msgstr "Anterior" #: scene/gui/control.cpp msgid "Mouse" -msgstr "Mouse" +msgstr "Rato" #: scene/gui/control.cpp msgid "Default Cursor Shape" diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po index 8e574f992d..eb7b2ffde0 100644 --- a/editor/translations/pt_BR.po +++ b/editor/translations/pt_BR.po @@ -20,7 +20,7 @@ # MalcomRF <malcomkbk@gmail.com>, 2017. # Marcus Correia <marknokalt@live.com>, 2017-2018. # Michael Alexsander Silva Dias <michaelalexsander@protonmail.com>, 2017-2018. -# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019, 2021. +# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019, 2021, 2023. # Rodolfo R Gomes <rodolforg@gmail.com>, 2017-2018, 2019. # Tiago Almeida <thyagoeap@gmail.com>, 2017. # Mauricio Luan Carneiro deSouza <newmailmlcs@gmail.com>, 2018. @@ -156,13 +156,14 @@ # Murilo Gama <murilovsky2030@gmail.com>, 2022. # Kauã Azevedo <Kazevic@pm.me>, 2022. # Zer0-Zer0 <dankmemerson@tutanota.com>, 2022. +# Levi Ferreira <leviferreiramorais@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: 2016-05-30\n" -"PO-Revision-Date: 2022-12-10 02:13+0000\n" -"Last-Translator: Julio Yagami <juliohenrique31501234@hotmail.com>\n" +"PO-Revision-Date: 2023-01-14 00:01+0000\n" +"Last-Translator: Levi Ferreira <leviferreiramorais@gmail.com>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "godot-engine/godot/pt_BR/>\n" "Language: pt_BR\n" @@ -170,7 +171,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -11075,7 +11076,7 @@ msgstr "Perspectiva Traseira" msgid " [auto]" msgstr " [automático]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portais ativados]" @@ -14331,17 +14332,15 @@ msgid "Invalid project path (changed anything?)." msgstr "Caminho de projeto inválido (mudou alguma coisa?)." #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." msgstr "" -"Não foi possÃvel carregar project.godot no caminho do projeto (erro %d). Ele " -"pode estar ausente ou corrompido." +"Não foi possÃvel carregar project.godot em '%s' (erro %d). Ele pode estar " +"ausente ou corrompido." #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "Não é possÃvel abrir o projeto em '%s'." +msgstr "Não foi possÃvel salvar o projeto em '%s' (erro %d)." #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -16200,9 +16199,8 @@ msgid "Multithreaded Server" msgstr "Servidor com Multi-Thread" #: main/main.cpp -#, fuzzy msgid "RID Pool Prealloc" -msgstr "Pre-alocação de Pool RID" +msgstr "Pool de Prealocação de RID" #: main/main.cpp msgid "Debugger stdout" @@ -16310,7 +16308,7 @@ msgstr "Modelo de Thread" #: main/main.cpp msgid "Thread Safe BVH" -msgstr "" +msgstr "Thread Segura de BVH" #: main/main.cpp msgid "Handheld" @@ -16675,9 +16673,8 @@ msgid "Path Local" msgstr "Caminho Local" #: modules/csg/csg_shape.cpp -#, fuzzy msgid "Path Continuous U" -msgstr "Caminho ContÃnuo" +msgstr "Caminho Continuo U" #: modules/csg/csg_shape.cpp msgid "Path U Distance" @@ -16943,11 +16940,11 @@ msgstr "Contagem Escassa" #: modules/gltf/gltf_accessor.cpp msgid "Sparse Indices Buffer View" -msgstr "" +msgstr "Visualização de Buffer dos Indices Esparsos" #: modules/gltf/gltf_accessor.cpp msgid "Sparse Indices Byte Offset" -msgstr "" +msgstr "Deslocação de Byte dos Ãndices Esparsos" #: modules/gltf/gltf_accessor.cpp msgid "Sparse Indices Component Type" @@ -16955,11 +16952,11 @@ msgstr "Tipo de Componente de Ãndices Esparsos" #: modules/gltf/gltf_accessor.cpp msgid "Sparse Values Buffer View" -msgstr "" +msgstr "Visualização de Buffer dos Valores Esparsos" #: modules/gltf/gltf_accessor.cpp msgid "Sparse Values Byte Offset" -msgstr "" +msgstr "Deslocação de Byte dos Valores Esparsos" #: modules/gltf/gltf_buffer_view.cpp msgid "Buffer" @@ -16971,7 +16968,7 @@ msgstr "Largura do byte" #: modules/gltf/gltf_buffer_view.cpp msgid "Byte Stride" -msgstr "" +msgstr "Separação dos Bytes" #: modules/gltf/gltf_buffer_view.cpp msgid "Indices" @@ -17031,11 +17028,11 @@ msgstr "Pai" #: modules/gltf/gltf_node.cpp msgid "Xform" -msgstr "" +msgstr "Xform" #: modules/gltf/gltf_node.cpp scene/3d/mesh_instance.cpp msgid "Skin" -msgstr "" +msgstr "Pele" #: modules/gltf/gltf_node.cpp scene/3d/spatial.cpp msgid "Translation" @@ -17107,11 +17104,11 @@ msgstr "Fator Especular" #: modules/gltf/gltf_spec_gloss.cpp msgid "Spec Gloss Img" -msgstr "" +msgstr "Imagem Especular Lustrosa" #: modules/gltf/gltf_state.cpp msgid "Json" -msgstr "" +msgstr "Json" #: modules/gltf/gltf_state.cpp msgid "Major Version" @@ -17127,7 +17124,7 @@ msgstr "Dados do GLB" #: modules/gltf/gltf_state.cpp msgid "Use Named Skin Binds" -msgstr "" +msgstr "Usar Associações de Pele com nome" #: modules/gltf/gltf_state.cpp msgid "Buffer Views" @@ -17432,15 +17429,15 @@ msgstr "Exibir para as Lentes" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "Oversample" -msgstr "" +msgstr "Amostragem em excesso" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "K1" -msgstr "" +msgstr "K1" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "K2" -msgstr "" +msgstr "K2" #: modules/mono/csharp_script.cpp msgid "Class name can't be a reserved keyword" @@ -18019,7 +18016,7 @@ msgstr "Iterador" #: modules/visual_script/visual_script_flow_control.cpp msgid "for (elem) in (input):" -msgstr "" +msgstr "for (elem) in (input):" #: modules/visual_script/visual_script_flow_control.cpp msgid "Input type not iterable:" @@ -18191,7 +18188,7 @@ msgstr "Argumentos inválidos:" #: modules/visual_script/visual_script_nodes.cpp msgid "a if cond, else b" -msgstr "" +msgstr "a se cond, se não b" #: modules/visual_script/visual_script_nodes.cpp msgid "Var Name" @@ -18247,11 +18244,11 @@ msgstr "Obter Ãrvore de Cenas" #: modules/visual_script/visual_script_nodes.cpp msgid "Get Self" -msgstr "Obter Sà Mesmo" +msgstr "Obter Si Mesmo" #: modules/visual_script/visual_script_nodes.cpp msgid "CustomNode" -msgstr "" +msgstr "Nó Personalizado" #: modules/visual_script/visual_script_nodes.cpp msgid "Custom node has no _step() method, can't process graph." @@ -18269,7 +18266,7 @@ msgstr "" #: modules/visual_script/visual_script_nodes.cpp msgid "SubCall" -msgstr "" +msgstr "Sub-Chamada" #: modules/visual_script/visual_script_nodes.cpp scene/gui/graph_node.cpp msgid "Title" @@ -18301,11 +18298,11 @@ msgstr "Buscar VisualScript" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Yield" -msgstr "" +msgstr "Aguardar Retorno" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Wait" -msgstr "" +msgstr "Esperar" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "Next Frame" @@ -18325,7 +18322,7 @@ msgstr "Tempo de Espera" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "WaitSignal" -msgstr "" +msgstr "EsperarSinal" #: modules/visual_script/visual_script_yield_nodes.cpp msgid "WaitNodeSignal" @@ -18341,7 +18338,7 @@ msgstr "Modo de Escrita" #: modules/webrtc/webrtc_data_channel.h msgid "WebRTC" -msgstr "" +msgstr "WebRTC" #: modules/webrtc/webrtc_data_channel.h msgid "Max Channel In Buffer (KB)" @@ -18381,7 +18378,7 @@ msgstr "Servidor WebSocket" #: modules/websocket/websocket_server.cpp msgid "Bind IP" -msgstr "" +msgstr "Atrelar IP" #: modules/websocket/websocket_server.cpp msgid "Private Key" @@ -18441,11 +18438,11 @@ msgstr "Depurar Keystore" #: platform/android/export/export.cpp msgid "Debug Keystore User" -msgstr "" +msgstr "Usuário da Keystore de Depuração" #: platform/android/export/export.cpp msgid "Debug Keystore Pass" -msgstr "" +msgstr "Senha da Keystore de Depuração" #: platform/android/export/export.cpp msgid "Force System User" @@ -19033,43 +19030,43 @@ msgstr "Telas de Inicialização de Paisagem" #: platform/iphone/export/export.cpp msgid "iPhone 2436 X 1125" -msgstr "IPhone 2436 X 1125" +msgstr "iPhone 2436 X 1125" #: platform/iphone/export/export.cpp msgid "iPhone 2208 X 1242" -msgstr "" +msgstr "iPhone 2208 X 1242" #: platform/iphone/export/export.cpp msgid "iPad 1024 X 768" -msgstr "" +msgstr "iPad 1024 X 768" #: platform/iphone/export/export.cpp msgid "iPad 2048 X 1536" -msgstr "" +msgstr "iPad 2048 X 1536" #: platform/iphone/export/export.cpp msgid "Portrait Launch Screens" -msgstr "" +msgstr "Tela de Apresentação em Retrato" #: platform/iphone/export/export.cpp msgid "iPhone 640 X 960" -msgstr "" +msgstr "iPhone 640 X 960" #: platform/iphone/export/export.cpp msgid "iPhone 640 X 1136" -msgstr "" +msgstr "iPhone 640 X 1136" #: platform/iphone/export/export.cpp msgid "iPhone 750 X 1334" -msgstr "" +msgstr "iPhone 750 X 1334" #: platform/iphone/export/export.cpp msgid "iPhone 1125 X 2436" -msgstr "" +msgstr "iPhone 1125 X 2436" #: platform/iphone/export/export.cpp msgid "iPad 768 X 1024" -msgstr "" +msgstr "iPad 768 X 1024" #: platform/iphone/export/export.cpp msgid "iPad 1536 X 2048" diff --git a/editor/translations/ro.po b/editor/translations/ro.po index 906d6aee71..9e2d8b5c96 100644 --- a/editor/translations/ro.po +++ b/editor/translations/ro.po @@ -20,13 +20,15 @@ # Psynt <nichita@cadvegra.com>, 2022. # Ilie Adrian Avramescu <himark1977@protonmail.com>, 2022. # Andres Ene <grassiscomplex420@gmail.com>, 2022. +# Claudiu Ceia <claudiu.ceia@gmail.com>, 2022. +# Random Videos <istudordanadenis@gmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-11-22 20:37+0000\n" -"Last-Translator: Andres Ene <grassiscomplex420@gmail.com>\n" +"PO-Revision-Date: 2023-01-13 03:04+0000\n" +"Last-Translator: Random Videos <istudordanadenis@gmail.com>\n" "Language-Team: Romanian <https://hosted.weblate.org/projects/godot-engine/" "godot/ro/>\n" "Language: ro\n" @@ -35,7 +37,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -66,9 +68,8 @@ msgid "Delta Smoothing" msgstr "Netezirea Delta" #: core/bind/core_bind.cpp -#, fuzzy msgid "Low Processor Usage Mode" -msgstr "Mod Mutare" +msgstr "Mod utilizare redusă a procesorului" #: core/bind/core_bind.cpp msgid "Low Processor Usage Mode Sleep (µsec)" @@ -225,18 +226,16 @@ msgstr "Date" #: modules/gdscript/language_server/gdscript_language_server.cpp #: modules/webrtc/webrtc_data_channel.h modules/websocket/websocket_macros.h #: scene/gui/file_dialog.cpp -#, fuzzy msgid "Network" -msgstr "Analizator Network" +msgstr "ReÈ›ea" #: core/io/file_access_network.cpp -#, fuzzy msgid "Remote FS" -msgstr "ȘtergeÈ›i" +msgstr "Sistem de fiÈ™iere (FS) la distanță" #: core/io/file_access_network.cpp msgid "Page Size" -msgstr "Marime Pagina" +msgstr "Mărime Pagina" #: core/io/file_access_network.cpp msgid "Page Read Ahead" @@ -248,29 +247,27 @@ msgstr "Mod de blocare Activat" #: core/io/http_client.cpp msgid "Connection" -msgstr "Conexie" +msgstr "Conexiune" #: core/io/http_client.cpp msgid "Read Chunk Size" -msgstr "" +msgstr "Dimensiunea fragmentului de citire" #: core/io/marshalls.cpp msgid "Object ID" msgstr "ID Obiect" #: core/io/multiplayer_api.cpp core/io/packet_peer.cpp -#, fuzzy msgid "Allow Object Decoding" -msgstr "Activează Onion Skinning" +msgstr "Permite Decodarea Obiectelor" #: core/io/multiplayer_api.cpp scene/main/scene_tree.cpp msgid "Refuse New Network Connections" msgstr "Refuza Conexiuni noi pe retea" #: core/io/multiplayer_api.cpp scene/main/scene_tree.cpp -#, fuzzy msgid "Network Peer" -msgstr "Analizator Network" +msgstr "Peer de ReÈ›ea" #: core/io/multiplayer_api.cpp scene/animation/animation_player.cpp msgid "Root Node" @@ -286,15 +283,15 @@ msgstr "Mod Transfer" #: core/io/packet_peer.cpp msgid "Encode Buffer Max Size" -msgstr "" +msgstr "Dimensiunea Maximă a Bufferului de Encodare" #: core/io/packet_peer.cpp msgid "Input Buffer Max Size" -msgstr "" +msgstr "Dimensiunea Maximă a Bufferului de Intrare" #: core/io/packet_peer.cpp msgid "Output Buffer Max Size" -msgstr "" +msgstr "Dimensiunea Maximă a Bufferului de IeÈ™ire" #: core/io/packet_peer.cpp msgid "Stream Peer" @@ -302,11 +299,11 @@ msgstr "Fluxul Peer" #: core/io/stream_peer.cpp msgid "Big Endian" -msgstr "" +msgstr "Big Endian" #: core/io/stream_peer.cpp msgid "Data Array" -msgstr "" +msgstr "Matrice Date" #: core/io/stream_peer_ssl.cpp msgid "Blocking Handshake" @@ -367,9 +364,8 @@ msgid "Seed" msgstr "SeminÈ›e" #: core/math/random_number_generator.cpp -#, fuzzy msgid "State" -msgstr "Mod RotaÈ›ie" +msgstr "State" #: core/message_queue.cpp msgid "Message Queue" @@ -377,17 +373,15 @@ msgstr "Coada de mesaje" #: core/message_queue.cpp msgid "Max Size (KB)" -msgstr "" +msgstr "Dimensiune maximă (KB)" #: core/os/input.cpp -#, fuzzy msgid "Mouse Mode" -msgstr "Mod Mutare" +msgstr "Mod Maus" #: core/os/input.cpp -#, fuzzy msgid "Use Accumulated Input" -msgstr "Șterge Intrare(Input)" +msgstr "Utilizează Intrarea (Input) Acumulată" #: core/os/input_event.cpp editor/project_settings_editor.cpp #: servers/audio_server.cpp @@ -411,9 +405,8 @@ msgid "Meta" msgstr "Meta" #: core/os/input_event.cpp -#, fuzzy msgid "Command" -msgstr "Comunitate" +msgstr "Comandă" #: core/os/input_event.cpp #, fuzzy @@ -444,9 +437,8 @@ msgid "Echo" msgstr "Ecou" #: core/os/input_event.cpp scene/gui/base_button.cpp -#, fuzzy msgid "Button Mask" -msgstr "Adaugă în Grup" +msgstr "Mască Buton" #: core/os/input_event.cpp scene/2d/node_2d.cpp scene/gui/control.cpp msgid "Global Position" @@ -457,9 +449,8 @@ msgid "Factor" msgstr "Factor" #: core/os/input_event.cpp -#, fuzzy msgid "Button Index" -msgstr "Mod ÃŽn Jur" +msgstr "Indice Buton" #: core/os/input_event.cpp msgid "Doubleclick" @@ -498,9 +489,8 @@ msgid "Axis Value" msgstr "Valoarea Axei" #: core/os/input_event.cpp modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "Index" -msgstr "Mod ÃŽn Jur" +msgstr "Indice" #: core/os/input_event.cpp editor/project_settings_editor.cpp #: modules/visual_script/visual_script_nodes.cpp @@ -518,29 +508,26 @@ msgid "Delta" msgstr "Delta" #: core/os/input_event.cpp -#, fuzzy msgid "Channel" -msgstr "SchimbaÈ›i" +msgstr "Canal" #: core/os/input_event.cpp main/main.cpp -#, fuzzy msgid "Message" -msgstr "Sincronizează Modificările Scriptului" +msgstr "Mesaj" #: core/os/input_event.cpp -#, fuzzy msgid "Pitch" -msgstr "Dimensiune:" +msgstr "ÃŽnclinaÈ›ie" #: core/os/input_event.cpp scene/2d/cpu_particles_2d.cpp #: scene/2d/physics_body_2d.cpp scene/3d/cpu_particles.cpp #: scene/3d/physics_body.cpp scene/resources/particles_material.cpp msgid "Velocity" -msgstr "" +msgstr "Viteză (velocity)" #: core/os/input_event.cpp msgid "Instrument" -msgstr "" +msgstr "Instrument" #: core/os/input_event.cpp msgid "Controller Number" @@ -553,19 +540,16 @@ msgstr "Valoarea controlerului" #: core/project_settings.cpp editor/editor_node.cpp main/main.cpp #: platform/iphone/export/export.cpp platform/osx/export/export.cpp #: platform/windows/export/export.cpp -#, fuzzy msgid "Application" -msgstr "AcÈ›iune" +msgstr "AplicaÈ›ie" #: core/project_settings.cpp main/main.cpp -#, fuzzy msgid "Config" -msgstr "Configurare Snap" +msgstr "Configurare" #: core/project_settings.cpp -#, fuzzy msgid "Project Settings Override" -msgstr "Setări proiect..." +msgstr "Suprascriere setări proiect" #: core/project_settings.cpp core/resource.cpp #: editor/animation_track_editor.cpp editor/editor_autoload_settings.cpp @@ -596,29 +580,27 @@ msgstr "Execută" #: core/project_settings.cpp editor/editor_node.cpp #: editor/run_settings_dialog.cpp main/main.cpp msgid "Main Scene" -msgstr "" +msgstr "Scena Principală" #: core/project_settings.cpp -#, fuzzy msgid "Disable stdout" -msgstr "Dezactivat" +msgstr "Dezactivează stdout" #: core/project_settings.cpp -#, fuzzy msgid "Disable stderr" -msgstr "Dezactivat" +msgstr "Dezactivează stderr" #: core/project_settings.cpp msgid "Use Hidden Project Data Directory" -msgstr "" +msgstr "Utilizează directorul de date de proiect ascuns" #: core/project_settings.cpp msgid "Use Custom User Dir" -msgstr "" +msgstr "Utilizează Director de Utilizator Personalizat" #: core/project_settings.cpp msgid "Custom User Dir Name" -msgstr "" +msgstr "Nume de Director de Utilizator Personalizat" #: core/project_settings.cpp main/main.cpp #: platform/javascript/export/export.cpp platform/osx/export/export.cpp @@ -631,7 +613,7 @@ msgstr "AfiÈ™ează Tot" #: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp #: scene/3d/label_3d.cpp scene/gui/text_edit.cpp scene/resources/texture.cpp msgid "Width" -msgstr "" +msgstr "Lățime" #: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp #: modules/gltf/gltf_node.cpp modules/opensimplex/noise_texture.cpp @@ -640,21 +622,19 @@ msgstr "" #: scene/resources/font.cpp scene/resources/navigation_mesh.cpp #: scene/resources/primitive_meshes.cpp scene/resources/texture.cpp msgid "Height" -msgstr "" +msgstr "ÃŽnălÈ›ime" #: core/project_settings.cpp msgid "Always On Top" -msgstr "" +msgstr "Mereu Deasupra" #: core/project_settings.cpp -#, fuzzy msgid "Test Width" -msgstr "Stânga liniară" +msgstr "Lățime de Test" #: core/project_settings.cpp -#, fuzzy msgid "Test Height" -msgstr "Se Testează" +msgstr "ÃŽnălÈ›ime de Test" #: core/project_settings.cpp editor/animation_track_editor.cpp #: editor/editor_audio_buses.cpp main/main.cpp servers/audio_server.cpp @@ -662,9 +642,8 @@ msgid "Audio" msgstr "Sunet" #: core/project_settings.cpp -#, fuzzy msgid "Default Bus Layout" -msgstr "ÃŽncarcă Schema de Pistă Audio implicită." +msgstr "Schema de Pistă Audio Implicită" #: core/project_settings.cpp editor/editor_export.cpp #: editor/editor_file_system.cpp editor/editor_node.cpp @@ -687,73 +666,64 @@ msgstr "Căutare în extensii de fiÈ™iere" #: core/project_settings.cpp msgid "Script Templates Search Path" -msgstr "" +msgstr "Cale de Căutare pentru Șabloane de Scripturi" #: core/project_settings.cpp -#, fuzzy msgid "Version Control Autoload On Startup" -msgstr "Control versiune" +msgstr "ÃŽncărcare Automată de Control al Versiunii la Pornire" #: core/project_settings.cpp -#, fuzzy msgid "Version Control Plugin Name" -msgstr "Control versiune" +msgstr "Numele Pluginului de Control al Versiunii" #: core/project_settings.cpp scene/2d/collision_object_2d.cpp #: scene/3d/collision_object.cpp scene/gui/control.cpp -#, fuzzy msgid "Input" -msgstr "Adaugă Intrare(Input)" +msgstr "Intrare (Input)" #: core/project_settings.cpp msgid "UI Accept" -msgstr "" +msgstr "Acceptare (UI)" #: core/project_settings.cpp -#, fuzzy msgid "UI Select" -msgstr "Selectează" +msgstr "Selectează (UI)" #: core/project_settings.cpp msgid "UI Cancel" -msgstr "Anulare interfață utilizator" +msgstr "Anulare (UI)" #: core/project_settings.cpp -#, fuzzy msgid "UI Focus Next" -msgstr "Cale focalizare" +msgstr "Focalizează Urmatorul (UI)" #: core/project_settings.cpp -#, fuzzy msgid "UI Focus Prev" -msgstr "Cale focalizare" +msgstr "Focalizează Anteriorul (UI)" #: core/project_settings.cpp -#, fuzzy msgid "UI Left" -msgstr "Mod RotaÈ›ie" +msgstr "Stânga (UI)" #: core/project_settings.cpp -#, fuzzy msgid "UI Right" -msgstr "RotaÈ›ie poligon" +msgstr "Dreapta (UI)" #: core/project_settings.cpp msgid "UI Up" -msgstr "" +msgstr "Sus (UI)" #: core/project_settings.cpp -#, fuzzy msgid "UI Down" -msgstr "Descarcă" +msgstr "JUos (UI)" #: core/project_settings.cpp msgid "UI Page Up" -msgstr "Pagina UI în sus" +msgstr "Pagina Ssus (UI)" #: core/project_settings.cpp msgid "UI Page Down" -msgstr "" +msgstr "Pagină Jos (UI)" #: core/project_settings.cpp msgid "UI Home" @@ -783,7 +753,7 @@ msgstr "Cadru Fizic %" #: scene/3d/physics_body.cpp scene/resources/world.cpp #: servers/physics/space_sw.cpp servers/physics_server.cpp msgid "3D" -msgstr "" +msgstr "3D" #: core/project_settings.cpp #, fuzzy @@ -800,7 +770,7 @@ msgstr "Creează un Frate de Coliziune Trimesh" #: scene/main/viewport.cpp servers/visual/visual_server_scene.cpp #: servers/visual_server.cpp msgid "Rendering" -msgstr "" +msgstr "Randare" #: core/project_settings.cpp drivers/gles2/rasterizer_storage_gles2.cpp #: drivers/gles3/rasterizer_scene_gles3.cpp @@ -850,17 +820,16 @@ msgid "Max Functions" msgstr "FaceÈ›i FuncÈ›ia" #: core/project_settings.cpp scene/3d/vehicle_body.cpp -#, fuzzy msgid "Compression" -msgstr "Setare expresie" +msgstr "Compresie" #: core/project_settings.cpp msgid "Formats" -msgstr "" +msgstr "Formate" #: core/project_settings.cpp msgid "Zstd" -msgstr "" +msgstr "Zstd" #: core/project_settings.cpp msgid "Long Distance Matching" @@ -905,11 +874,11 @@ msgstr "Pachet Peer Stream" #: core/register_core_types.cpp msgid "Max Buffer (Power of 2)" -msgstr "" +msgstr "Buffer Maxim (Putere de-a lui 2)" #: core/register_core_types.cpp editor/editor_settings.cpp main/main.cpp msgid "SSL" -msgstr "" +msgstr "SSL" #: core/register_core_types.cpp main/main.cpp #, fuzzy @@ -941,7 +910,7 @@ msgstr "Resursă" #: core/translation.cpp editor/project_settings_editor.cpp msgid "Locale" -msgstr "" +msgstr "Local" #: core/translation.cpp #, fuzzy @@ -986,17 +955,17 @@ msgstr "EiB" #: drivers/gles3/rasterizer_scene_gles3.cpp #: drivers/gles3/rasterizer_storage_gles3.cpp modules/gltf/gltf_state.cpp msgid "Buffers" -msgstr "" +msgstr "Buffere" #: drivers/gles2/rasterizer_canvas_base_gles2.cpp #: drivers/gles3/rasterizer_canvas_base_gles3.cpp msgid "Canvas Polygon Buffer Size (KB)" -msgstr "" +msgstr "Dimensiune Buffer Poligon de Canvas (KB)" #: drivers/gles2/rasterizer_canvas_base_gles2.cpp #: drivers/gles3/rasterizer_canvas_base_gles3.cpp msgid "Canvas Polygon Index Buffer Size (KB)" -msgstr "" +msgstr "Dimensiune Indice Buffer Poligon de Canvas (KB)" #: drivers/gles2/rasterizer_canvas_base_gles2.cpp #: drivers/gles3/rasterizer_canvas_base_gles3.cpp editor/editor_settings.cpp @@ -1040,11 +1009,11 @@ msgstr "Utilizarea eÈ™antionării bicubice" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Elements" -msgstr "" +msgstr "Numărul Maxim de Elemente Care se Pot Randa" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Renderable Lights" -msgstr "" +msgstr "Numărul Maxim de Lumini Care se Pot Randa" #: drivers/gles3/rasterizer_scene_gles3.cpp #, fuzzy @@ -1053,7 +1022,7 @@ msgstr "Centrează SelecÈ›ia" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Max Lights Per Object" -msgstr "" +msgstr "Numărul Maxim de Lumini per Obiect" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Subsurface Scattering" @@ -1087,7 +1056,7 @@ msgstr "" #: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp msgid "High Quality" -msgstr "" +msgstr "Calitate ÃŽnaltă" #: drivers/gles3/rasterizer_storage_gles3.cpp msgid "Blend Shape Max Buffer Size (KB)" @@ -1190,7 +1159,7 @@ msgstr "RotaÈ›ie" #: editor/animation_track_editor.cpp editor/script_editor_debugger.cpp #: modules/visual_script/visual_script_nodes.cpp scene/gui/range.cpp msgid "Value" -msgstr "" +msgstr "Valoare" #: editor/animation_track_editor.cpp #, fuzzy @@ -1200,14 +1169,14 @@ msgstr "Cantitate:" #: editor/animation_track_editor.cpp main/main.cpp #: modules/mono/mono_gd/gd_mono.cpp msgid "Args" -msgstr "" +msgstr "Argumente" #: editor/animation_track_editor.cpp editor/editor_settings.cpp #: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp #: modules/gltf/gltf_light.cpp modules/visual_script/visual_script_nodes.cpp #: scene/3d/physics_body.cpp scene/resources/visual_shader_nodes.cpp msgid "Type" -msgstr "" +msgstr "Tip" #: editor/animation_track_editor.cpp #, fuzzy @@ -1380,7 +1349,7 @@ msgstr "Dimensiune:" #: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Type:" -msgstr "" +msgstr "Tip:" #: editor/animation_track_editor.cpp #, fuzzy @@ -1646,7 +1615,7 @@ msgstr "Anim MutaÈ›i Cheie" #: servers/camera/camera_feed.cpp servers/physics_2d_server.cpp #: servers/physics_server.cpp msgid "Transform" -msgstr "" +msgstr "Transformă" #: editor/animation_track_editor.cpp editor/editor_help.cpp msgid "Methods" @@ -2667,7 +2636,7 @@ msgstr "Nume nevalid." #: editor/editor_autoload_settings.cpp msgid "Cannot begin with a digit." -msgstr "" +msgstr "Nu poate începe cu o cifră" #: editor/editor_autoload_settings.cpp msgid "Valid characters:" @@ -2949,7 +2918,7 @@ msgstr "Culoare uniformă." #: editor/editor_export.cpp msgid "64 Bits" -msgstr "" +msgstr "64 de biÈ›i" #: editor/editor_export.cpp msgid "Embed PCK" @@ -3207,6 +3176,8 @@ msgstr "OpÈ›iunii Extra:" #: editor/editor_feature_profile.cpp msgid "Create or import a profile to edit available classes and properties." msgstr "" +"Creează sau importă un profil pentru a edita clasele si proprietățile " +"disponibile" #: editor/editor_feature_profile.cpp msgid "New profile name:" @@ -3347,7 +3318,7 @@ msgstr "ComutaÈ›i FiÈ™iere Ascunse" #: editor/editor_file_dialog.cpp msgid "Disable Overwrite Warning" -msgstr "" +msgstr "Opreste suprascrierea avertizărilor" #: editor/editor_file_dialog.cpp msgid "Go Back" @@ -3496,7 +3467,7 @@ msgstr "Proprietățile Temei" #: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp #: scene/resources/gradient.cpp msgid "Colors" -msgstr "" +msgstr "Culori" #: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp msgid "Constants" @@ -3504,16 +3475,16 @@ msgstr "Constante" #: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp msgid "Fonts" -msgstr "" +msgstr "Fonturi" #: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp #: platform/iphone/export/export.cpp msgid "Icons" -msgstr "" +msgstr "Icoană" #: editor/editor_help.cpp msgid "Styles" -msgstr "" +msgstr "Stiluri" #: editor/editor_help.cpp msgid "Enumerations" @@ -3645,7 +3616,7 @@ msgstr "Proprietate:" #: editor/editor_inspector.cpp editor/editor_spin_slider.cpp msgid "Label" -msgstr "" +msgstr "Etichetă" #: editor/editor_inspector.cpp editor/editor_spin_slider.cpp #: scene/resources/default_theme/default_theme.cpp @@ -4213,14 +4184,14 @@ msgid "Unable to load addon script from path: '%s'." msgstr "Nu a putut fi încărcat scriptul add-on din calea: '%s'." #: editor/editor_node.cpp -#, fuzzy msgid "" "Unable to load addon script from path: '%s'. This might be due to a code " "error in that script.\n" "Disabling the addon at '%s' to prevent further errors." msgstr "" "Imposibil de încărcat scriptul addon din cale: '%s' Se pare că există o " -"eroare în cod, verificaÈ›i sintaxa." +"eroare în cod, verificaÈ›i sintaxa.\n" +"Dezactivez addon-ul de la '%s' pentru a preveni erori ulterioare." #: editor/editor_node.cpp msgid "" @@ -7317,9 +7288,8 @@ msgid "Generating Lightmaps" msgstr "Se Genereaza Lightmaps" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Generating for Mesh:" -msgstr "Se Generează pentru Mesh: " +msgstr "Se Generează pentru Mesh:" #: editor/import/resource_importer_scene.cpp msgid "Running Custom Script..." @@ -8967,36 +8937,32 @@ msgid "Center Top" msgstr "Centrează SelecÈ›ia" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Center Right" -msgstr "RotaÈ›ie poligon" +msgstr "Centrează Dreapta" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Center Bottom" -msgstr "Centrează SelecÈ›ia" +msgstr "Centrează Jos" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Center" -msgstr "" +msgstr "Centrează" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Left Wide" -msgstr "Stânga liniară" +msgstr "Stânga Lat" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Top Wide" -msgstr "" +msgstr "Sus Lat" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Right Wide" -msgstr "Dreapta liniară" +msgstr "Dreapta Lat" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Bottom Wide" -msgstr "" +msgstr "Jos Lat" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "VCenter Wide" @@ -9032,6 +8998,9 @@ msgid "" "Project Camera Override\n" "Overrides the running project's camera with the editor viewport camera." msgstr "" +"Suprascrierea Camerei de Proiect\n" +"Suprascrie camera proiectului care rulează cu camera de vizualizare a " +"editorului." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9040,48 +9009,45 @@ msgid "" "No project instance running. Run the project from the editor to use this " "feature." msgstr "" +"Suprascrierea Camerei de Proiect\n" +"Nicio instanță de proiect nu rulează. RulaÈ›i proiectul din editor pentru a " +"utiliza această caracteristică." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Lock Selected" -msgstr "Selectează" +msgstr "Blochează SelecÈ›ia" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Unlock Selected" -msgstr "" +msgstr "Deblochează SelecÈ›ia" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Group Selected" -msgstr "ElminaÈ›i SelecÈ›ia" +msgstr "Grupează SelecÈ›ia" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Ungroup Selected" -msgstr "ElminaÈ›i SelecÈ›ia" +msgstr "DegrupaÈ›i selecÈ›ia" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Paste Pose" msgstr "LipeÈ™te Postura" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Clear Guides" -msgstr "Curăță Postura" +msgstr "Elimină Ghidurile" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Create Custom Bone(s) from Node(s)" -msgstr "Creează Puncte de Emisie Din Mesh" +msgstr "Crează Oase personalizate din Noduri" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Clear Bones" -msgstr "Curăță Postura" +msgstr "Elimină Oase" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Make IK Chain" @@ -9112,36 +9078,31 @@ msgstr "Selectare mod" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Drag: Rotate selected node around pivot." -msgstr "ȘtergeÈ›i pista selectată." +msgstr "Trage: RoteÈ™te nodul selectat în jurul pivotului." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Alt+Drag: Move selected node." -msgstr "Alt+Trage: Mutare" +msgstr "Alt+Trage: Mută nodul selectat." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Alt+Drag: Scale selected node." -msgstr "Alt+Trage: Mutare" +msgstr "Alt+Trage: Scalează nodul selectat." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "V: Set selected node's pivot position." -msgstr "ȘtergeÈ›i pista selectată." +msgstr "V: Setează poziÈ›ia pivotului nodului selectat." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Alt+RMB: Show list of all nodes at position clicked, including locked." msgstr "" -"Arată o listă a tuturor obiectelor la poziÈ›ia clickului\n" -"(similar cu Alt+RMB în modul selectare)." +"Alt+RMB: Arată o listă a tuturor nodurilor la poziÈ›ia clickului, inclusiv " +"cele blocate." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "RMB: Add node at position clicked." -msgstr "" +msgstr "RMB: Adaugă nod la poziÈ›ia clickului." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9155,13 +9116,12 @@ msgstr "Mod RotaÈ›ie" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Scale Mode" -msgstr "Mod Redimensionare (R)" +msgstr "Mod Redimensionare" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Shift: Scale proportionally." -msgstr "" +msgstr "Shift: Redimensionare proporÈ›ională." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9189,21 +9149,18 @@ msgid "Toggle smart snapping." msgstr "ComutaÈ›i fixarea inteligentă." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Use Smart Snap" -msgstr "Utilizează Snap" +msgstr "Utilizează Snap Inteligent" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Toggle grid snapping." msgstr "Comutare grilă fixare." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Use Grid Snap" -msgstr "Snap Grilă" +msgstr "Utilizează Snap Grilă" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snapping Options" msgstr "OpÈ›iuni Snapping" @@ -9212,9 +9169,8 @@ msgid "Use Rotation Snap" msgstr "FoloseÈ™te RotaÈ›ia Snap" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Use Scale Snap" -msgstr "Utilizează Snap" +msgstr "Utilizează Snap Redimensionare" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap Relative" @@ -9225,9 +9181,8 @@ msgid "Use Pixel Snap" msgstr "Utilizează Pixel Snap" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Smart Snapping" -msgstr "Snapping inteligent" +msgstr "Snapping Inteligent" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9235,34 +9190,28 @@ msgid "Configure Snap..." msgstr "Configurare Snap..." #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snap to Parent" -msgstr "Snap către părinte" +msgstr "Snap către Părinte" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snap to Node Anchor" -msgstr "Snap către ancora nodului" +msgstr "Snap către Ancora Nodului" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snap to Node Sides" -msgstr "Snap pe feÈ›ele nodului" +msgstr "Snap pe FeÈ›ele Nodului" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snap to Node Center" -msgstr "Snap către ancora nodului" +msgstr "Snap către Centrul Nodului" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snap to Other Nodes" -msgstr "Snap către alte noduri" +msgstr "Snap către Alte Noduri" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Snap to Guides" -msgstr "Snap pe ghizi" +msgstr "Snap pe Ghiduri" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9271,9 +9220,8 @@ msgstr "Imobilizează obiectul selectat (nu poate fi miÈ™cat)." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Lock Selected Node(s)" -msgstr "Selectează" +msgstr "Blochează Nodurile Selectate" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9282,9 +9230,8 @@ msgstr "Remobilizează obiectul selectat (poate fi miÈ™cat)." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Unlock Selected Node(s)" -msgstr "Selectează" +msgstr "Deblochează Nodurile Selectate" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9293,9 +9240,8 @@ msgstr "Asigură-te că nu pot fi selectaÈ›i copiii obiectului." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Group Selected Node(s)" -msgstr "ElminaÈ›i SelecÈ›ia" +msgstr "Grupează Nodurile Selectate" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -9304,14 +9250,12 @@ msgstr "Restaurează abilitatea copiilor obiectului de a fi selectaÈ›i." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Ungroup Selected Node(s)" -msgstr "ElminaÈ›i SelecÈ›ia" +msgstr "Degrupează Nodurile Selectate" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Skeleton Options" -msgstr "Singleton (Unicat)" +msgstr "OpÈ›iuni Schelet" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Bones" @@ -9322,9 +9266,8 @@ msgid "Make Custom Bone(s) from Node(s)" msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Clear Custom Bones" -msgstr "Curăță Oasele" +msgstr "Curăță Oasele Personalizate" #. TRANSLATORS: Noun, name of the 2D/3D View menus. #: editor/plugins/canvas_item_editor_plugin.cpp @@ -9333,23 +9276,20 @@ msgid "View" msgstr "Perspectivă" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Show" -msgstr "Arată Grila" +msgstr "Arată" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Show When Snapping" -msgstr "Snapping inteligent" +msgstr "Arată Când Faci Snap" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Hide" -msgstr "" +msgstr "Ascunde" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Toggle Grid" -msgstr "Comutare mod" +msgstr "Comutare Grilă" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/polygon_2d_editor_plugin.cpp @@ -9378,7 +9318,7 @@ msgstr "Arată Fereastra de Lucru" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Show Group And Lock Icons" -msgstr "" +msgstr "Arată Pictogramele de Grupare È™i Blocare" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Center Selection" @@ -9390,7 +9330,7 @@ msgstr "ÃŽncadrează în Ecran SelecÈ›ia" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Preview Canvas Scale" -msgstr "" +msgstr "Previzualizare Scară Canvas" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Layout" @@ -9421,14 +9361,12 @@ msgid "" msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Auto Insert Key" -msgstr "Anim InseraÈ›i Cheie" +msgstr "Inserare Automată a Cheii" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Animation Key and Pose Options" -msgstr "Lungime AnimaÈ›ie (în secunde)" +msgstr "Optiuni pentru Chei AnimaÈ›ie È™i Postură" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key (Existing Tracks)" @@ -9443,9 +9381,8 @@ msgid "Clear Pose" msgstr "Curăță Postura" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Add Node Here" -msgstr "Adaugă punct" +msgstr "Adaugă Nod Aici" #: editor/plugins/canvas_item_editor_plugin.cpp #, fuzzy @@ -9467,49 +9404,43 @@ msgstr "Perspectivă Snap" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Zoom to 3.125%" -msgstr "" +msgstr "Magnificare la 3.125%" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Zoom to 6.25%" -msgstr "" +msgstr "Magnificare la 6.25%" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Zoom to 12.5%" -msgstr "" +msgstr "Magnificare la 12.5%" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Zoom to 25%" -msgstr "Departare" +msgstr "Magnificare la 25%" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Zoom to 50%" -msgstr "Departare" +msgstr "Magnificare la 50%" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Zoom to 100%" -msgstr "Departare" +msgstr "Magnificare la 100%" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Zoom to 200%" -msgstr "Departare" +msgstr "Magnificare la 200%" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Zoom to 400%" -msgstr "Departare" +msgstr "Magnificare la 400%" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Zoom to 800%" -msgstr "Departare" +msgstr "Magnificare la 800%" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Zoom to 1600%" -msgstr "" +msgstr "Magnificare la 1600%" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Adding %s..." @@ -9530,9 +9461,8 @@ msgid "Error instancing scene from %s" msgstr "Eroare la instanÈ›ierea scenei din %s" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Change Default Type" -msgstr "Schimbă tipul implicit" +msgstr "Schimbă Tipul Implicit" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -9543,9 +9473,8 @@ msgstr "" "Trage & lasă + Shift: Schimbă tipul nodului" #: editor/plugins/collision_polygon_editor_plugin.cpp -#, fuzzy msgid "Create Polygon3D" -msgstr "Crează Poligon" +msgstr "Crează Poligon3D" #: editor/plugins/collision_polygon_editor_plugin.cpp msgid "Edit Poly" @@ -9595,7 +9524,7 @@ msgstr "Mască de Emisie" #: editor/plugins/cpu_particles_2d_editor_plugin.cpp #: editor/plugins/particles_2d_editor_plugin.cpp msgid "Solid Pixels" -msgstr "" +msgstr "Pixeli Solizi" #: editor/plugins/cpu_particles_2d_editor_plugin.cpp #: editor/plugins/particles_2d_editor_plugin.cpp @@ -9618,9 +9547,8 @@ msgid "Emission Colors" msgstr "Culori de Emisie" #: editor/plugins/cpu_particles_editor_plugin.cpp -#, fuzzy msgid "CPUParticles" -msgstr "Particule" +msgstr "ParticuleCPU" #: editor/plugins/cpu_particles_editor_plugin.cpp #: editor/plugins/particles_editor_plugin.cpp @@ -9667,29 +9595,24 @@ msgid "Load Curve Preset" msgstr "ÃŽncarcă Presetare a Curbei" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Add Point" -msgstr "Adaugă punct" +msgstr "Adaugă Punct" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Remove Point" -msgstr "Elimină punct" +msgstr "Elimină Punct" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Left Linear" -msgstr "Stânga liniară" +msgstr "Stânga Liniară" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Right Linear" -msgstr "Dreapta liniară" +msgstr "Dreapta Liniară" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Load Preset" -msgstr "ÃŽncarcă presetare" +msgstr "ÃŽncarcă Presetare" #: editor/plugins/curve_editor_plugin.cpp msgid "Remove Curve Point" @@ -9704,9 +9627,8 @@ msgid "Hold Shift to edit tangents individually" msgstr "Èšine apăsat Shift pentru a edita individual tangentele" #: editor/plugins/curve_editor_plugin.cpp -#, fuzzy msgid "Right click to add point" -msgstr "Click Drept: Ștergere punct" +msgstr "Click dreapta pentru adăugare punct" #: editor/plugins/gi_probe_editor_plugin.cpp msgid "Bake GI Probe" @@ -9714,7 +9636,7 @@ msgstr "Procesează Sonda GI" #: editor/plugins/gradient_editor_plugin.cpp msgid "Gradient Edited" -msgstr "" +msgstr "Gradient Dditat" #: editor/plugins/gradient_texture_2d_editor_plugin.cpp msgid "Swap GradientTexture2D Fill Points" @@ -9735,18 +9657,18 @@ msgstr "Comutare mod" #: scene/gui/rich_text_label.cpp scene/gui/text_edit.cpp #: scene/resources/primitive_meshes.cpp msgid "Text" -msgstr "" +msgstr "Text" #: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp main/main.cpp #: platform/osx/export/export.cpp platform/windows/export/export.cpp #: scene/gui/button.cpp scene/gui/item_list.cpp msgid "Icon" -msgstr "" +msgstr "Pictogramă" #: editor/plugins/item_list_editor_plugin.cpp msgid "ID" -msgstr "" +msgstr "ID" #: editor/plugins/item_list_editor_plugin.cpp #: scene/resources/default_theme/default_theme.cpp @@ -11288,7 +11210,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" @@ -18656,14 +18578,12 @@ msgid "Var Name" msgstr "Nume" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "VariableGet not found in script:" -msgstr "Metoda nu a fost găsită în obiect: " +msgstr "VariableGet nu a fost găsită în obiect:" #: modules/visual_script/visual_script_nodes.cpp -#, fuzzy msgid "VariableSet not found in script:" -msgstr "Metoda nu a fost găsită în obiect: " +msgstr "Metoda VariableSet nu a fost găsită în obiect:" #: modules/visual_script/visual_script_nodes.cpp msgid "Preload" @@ -19354,11 +19274,8 @@ msgid "Signing debug %s..." msgstr "" #: platform/android/export/export_plugin.cpp -#, fuzzy msgid "Signing release %s..." -msgstr "" -"Se Scanează FiÈ™ierele,\n" -"Te Rog AÈ™teaptă..." +msgstr "Se semnează release-ul %s..." #: platform/android/export/export_plugin.cpp msgid "Could not find keystore, unable to export." diff --git a/editor/translations/ru.po b/editor/translations/ru.po index d746bb61ad..97e9723383 100644 --- a/editor/translations/ru.po +++ b/editor/translations/ru.po @@ -11029,7 +11029,7 @@ msgstr "Задний перÑпективный" msgid " [auto]" msgstr " [авто]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [порталы активны]" diff --git a/editor/translations/si.po b/editor/translations/si.po index d0fcba8cfd..af22d7b2d2 100644 --- a/editor/translations/si.po +++ b/editor/translations/si.po @@ -10744,7 +10744,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/sk.po b/editor/translations/sk.po index 43c2fa6b5b..4f4e1107f3 100644 --- a/editor/translations/sk.po +++ b/editor/translations/sk.po @@ -12,13 +12,14 @@ # Anonymous <noreply@weblate.org>, 2020. # Mario-projects-dev <m.vitek.mv@gmail.com>, 2021. # EliÅ¡ka Fichnová <eliska@fichna.sk>, 2021. +# Adam Å vidroň <adsvidro@gmail.com>, 2022. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-07-07 15:34+0000\n" -"Last-Translator: EliÅ¡ka Fichnová <eliska@fichna.sk>\n" +"PO-Revision-Date: 2022-12-21 07:01+0000\n" +"Last-Translator: Adam Å vidroň <adsvidro@gmail.com>\n" "Language-Team: Slovak <https://hosted.weblate.org/projects/godot-engine/" "godot/sk/>\n" "Language: sk\n" @@ -26,7 +27,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 4.8-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -34,7 +35,7 @@ msgstr "" #: core/bind/core_bind.cpp msgid "Clipboard" -msgstr "" +msgstr "Schránka" #: core/bind/core_bind.cpp #, fuzzy @@ -11289,7 +11290,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/sl.po b/editor/translations/sl.po index 864dac1b8d..3605bbeaf5 100644 --- a/editor/translations/sl.po +++ b/editor/translations/sl.po @@ -11456,7 +11456,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/sq.po b/editor/translations/sq.po index 1215b7dbcb..e4d3ef6732 100644 --- a/editor/translations/sq.po +++ b/editor/translations/sq.po @@ -11222,7 +11222,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po index 419e33c494..c2d0ffe462 100644 --- a/editor/translations/sr_Cyrl.po +++ b/editor/translations/sr_Cyrl.po @@ -12040,7 +12040,7 @@ msgstr "ПерÑпективна пројекција" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po index 7973756c7e..5693d06931 100644 --- a/editor/translations/sr_Latn.po +++ b/editor/translations/sr_Latn.po @@ -10752,7 +10752,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/sv.po b/editor/translations/sv.po index 04965e6c69..dff36498be 100644 --- a/editor/translations/sv.po +++ b/editor/translations/sv.po @@ -25,15 +25,16 @@ # Leon <joel.lundborg@gmail.com>, 2021, 2022. # Kent Jofur <kent.jofur@gmail.com>, 2021. # Alex25820 <alexs25820@gmail.com>, 2021. -# Björn Ã…kesson <bjorn.akesson@gmail.com>, 2022. +# Björn Ã…kesson <bjorn.akesson@gmail.com>, 2022, 2023. # Kenny Andersson <kenny@ordinary.se>, 2022. +# Ludvig Svenonius <ludvig.svenonius@protonmail.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-09-29 19:16+0000\n" -"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n" +"PO-Revision-Date: 2023-01-20 11:20+0000\n" +"Last-Translator: Ludvig Svenonius <ludvig.svenonius@protonmail.com>\n" "Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/" "godot/sv/>\n" "Language: sv\n" @@ -41,7 +42,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15.1\n" #: core/bind/core_bind.cpp main/main.cpp #, fuzzy @@ -704,9 +705,8 @@ msgid "Script Templates Search Path" msgstr "Sökväg för skriptmallar" #: core/project_settings.cpp -#, fuzzy msgid "Version Control Autoload On Startup" -msgstr "Versionshantering" +msgstr "Automatisk Inläsning av Versionskontroll vid Start" #: core/project_settings.cpp #, fuzzy @@ -8287,7 +8287,7 @@ msgstr "" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Autoplay on Load" -msgstr "" +msgstr "Spela upp automatiskt efter inladdning" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Enable Onion Skinning" @@ -11363,7 +11363,7 @@ msgstr "Perspektiv" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" @@ -15031,19 +15031,19 @@ msgstr "" #: editor/project_settings_editor.cpp msgid "Physical Key" -msgstr "" +msgstr "Fysisk tangent" #: editor/project_settings_editor.cpp msgid "Key " -msgstr "Nyckel " +msgstr "Tangent " #: editor/project_settings_editor.cpp msgid "Joy Button" -msgstr "" +msgstr "Styrspaksknapp" #: editor/project_settings_editor.cpp msgid "Joy Axis" -msgstr "" +msgstr "Styrspaksaxel" #: editor/project_settings_editor.cpp msgid "Mouse Button" @@ -15072,9 +15072,8 @@ msgid "Add Input Action Event" msgstr "" #: editor/project_settings_editor.cpp -#, fuzzy msgid "All Devices" -msgstr "Enhet" +msgstr "Alla Enheter" #: editor/project_settings_editor.cpp msgid " (Physical)" @@ -20908,11 +20907,11 @@ msgstr "" #: scene/2d/area_2d.cpp scene/3d/area.cpp msgid "Monitoring" -msgstr "" +msgstr "Övervakning" #: scene/2d/area_2d.cpp scene/3d/area.cpp msgid "Monitorable" -msgstr "" +msgstr "Övervakningsbar" #: scene/2d/area_2d.cpp scene/3d/area.cpp #, fuzzy @@ -20985,7 +20984,7 @@ msgstr "SlÃ¥ pÃ¥/av Autoplay" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/audio/audio_stream_player.cpp msgid "Stream Paused" -msgstr "" +msgstr "Pausad" #: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp #: scene/3d/light.cpp scene/3d/reflection_probe.cpp @@ -25655,39 +25654,32 @@ msgid "Swap OK Cancel" msgstr "Avbryt" #: scene/register_scene_types.cpp -#, fuzzy msgid "Layer Names" -msgstr "Namn" +msgstr "Skiktnamn" #: scene/register_scene_types.cpp -#, fuzzy msgid "2D Render" -msgstr "Renderare:" +msgstr "2D-Rendering" #: scene/register_scene_types.cpp -#, fuzzy msgid "3D Render" -msgstr "Renderare:" +msgstr "3D-Rendering" #: scene/register_scene_types.cpp -#, fuzzy msgid "2D Physics" -msgstr "Fysik Bildruta %" +msgstr "2D-Fysik" #: scene/register_scene_types.cpp -#, fuzzy msgid "3D Physics" -msgstr "Fysik Bildruta %" +msgstr "3D-Fysik" #: scene/register_scene_types.cpp -#, fuzzy msgid "2D Navigation" -msgstr "Animations-Node" +msgstr "2D-Navigation" #: scene/register_scene_types.cpp -#, fuzzy msgid "3D Navigation" -msgstr "Animations-Node" +msgstr "3D-Navigation" #: scene/register_scene_types.cpp msgid "Use hiDPI" diff --git a/editor/translations/te.po b/editor/translations/te.po index 22474ca4ba..f8a1f82710 100644 --- a/editor/translations/te.po +++ b/editor/translations/te.po @@ -10590,7 +10590,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/th.po b/editor/translations/th.po index 5f4ee76a4d..c41428e6d1 100644 --- a/editor/translations/th.po +++ b/editor/translations/th.po @@ -11270,7 +11270,7 @@ msgstr "เพà¸à¸£à¹Œà¸ªà¹€à¸›à¸à¸—ีฟ" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/tl.po b/editor/translations/tl.po index 670e52056d..fa5f9a9aea 100644 --- a/editor/translations/tl.po +++ b/editor/translations/tl.po @@ -10910,7 +10910,7 @@ msgstr "" msgid " [auto]" msgstr " [kusa]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [mga aktibong portal]" diff --git a/editor/translations/tr.po b/editor/translations/tr.po index ac4b509150..73fbaec2cb 100644 --- a/editor/translations/tr.po +++ b/editor/translations/tr.po @@ -11032,7 +11032,7 @@ msgstr "Arka Perspektif" msgid " [auto]" msgstr " [Oto]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [portallar aktif]" diff --git a/editor/translations/uk.po b/editor/translations/uk.po index f9a6c787a5..a8d989d5ee 100644 --- a/editor/translations/uk.po +++ b/editor/translations/uk.po @@ -17,21 +17,23 @@ # Микола Тимошенко <9081@ukr.net>, 2020. # Miroslav <zinmirx@gmail.com>, 2020. # IllusiveMan196 <hamsterrv@gmail.com>, 2021, 2022. -# KazanskiyMaks <kazanskiy.maks@gmail.com>, 2022. +# KazanskiyMaks <kazanskiy.maks@gmail.com>, 2022, 2023. # МироÑлав <hlopukmyroslav@gmail.com>, 2022. # Ostap <ostapbataj79@gmail.com>, 2022. # Wald Sin <naaveranos@gmail.com>, 2022. # Гліб Соколов <ramithes@i.ua>, 2022. # Max Donchenko <maxx.donchenko@gmail.com>, 2022. # Artem <artem@molotov.work>, 2022. -# Teashrock <kajitsu22@gmail.com>, 2022. +# Teashrock <kajitsu22@gmail.com>, 2022, 2023. +# kirill7606 <k7606irill@gmail.com>, 2022. +# Alex <anna.loban@yahoo.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Ukrainian (Godot Engine)\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-10-03 12:44+0000\n" -"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" +"PO-Revision-Date: 2023-01-08 09:47+0000\n" +"Last-Translator: KazanskiyMaks <kazanskiy.maks@gmail.com>\n" "Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/" "godot/uk/>\n" "Language: uk\n" @@ -40,7 +42,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -60,27 +62,27 @@ msgstr "Код виходу" #: core/bind/core_bind.cpp msgid "V-Sync Enabled" -msgstr "Увімкнено верт. Ñинхронізацію" +msgstr "Увімкнено вертикальну Ñинхронізацію" #: core/bind/core_bind.cpp main/main.cpp msgid "V-Sync Via Compositor" -msgstr "Верт. Ñинхр. через заÑіб композиції" +msgstr "Вертикальна ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ñ‡ÐµÑ€ÐµÐ· заÑіб композиції" #: core/bind/core_bind.cpp main/main.cpp msgid "Delta Smoothing" -msgstr "Ð—Ð³Ð»Ð°Ð´Ð¶ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ñ–Ð·Ð½Ð¸Ñ†Ñ–" +msgstr "Дельта-згладжуваннÑ" #: core/bind/core_bind.cpp msgid "Low Processor Usage Mode" -msgstr "Режим низького ÑÐ¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора" +msgstr "Режим низького викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора" #: core/bind/core_bind.cpp msgid "Low Processor Usage Mode Sleep (µsec)" -msgstr "ПриÑиплÑÐ½Ð½Ñ Ñƒ режимі низького ÑÐ¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора (мкÑ)" +msgstr "Ð§Ð°Ñ Ñну в режимі низького викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора (мкÑ)" #: core/bind/core_bind.cpp main/main.cpp platform/uwp/os_uwp.cpp msgid "Keep Screen On" -msgstr "Залишити зневаджувач відкритим" +msgstr "Ðе вимикати екран" #: core/bind/core_bind.cpp msgid "Min Window Size" @@ -4533,7 +4535,7 @@ msgstr "Перезавантажити поточний проєкт" #: editor/editor_node.cpp msgid "Quit to Project List" -msgstr "Вийти в ÑпиÑок проєктів" +msgstr "Вийти до ÑпиÑку проєктів" #: editor/editor_node.cpp msgid "Deploy with Remote Debug" @@ -5496,9 +5498,8 @@ msgid "Mouse Extra Buttons Navigate History" msgstr "Додаткові кнопки миші Ð´Ð»Ñ Ð½Ð°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ— журналом" #: editor/editor_settings.cpp -#, fuzzy msgid "Drag And Drop Selection" -msgstr "ПеретÑгніть виділене" +msgstr "Ð’Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Drag And Drop" #: editor/editor_settings.cpp msgid "Stay In Script Editor On Node Selected" @@ -10955,7 +10956,7 @@ msgstr "Задній перÑпективний" msgid " [auto]" msgstr " [авто]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [портали активні]" @@ -14219,17 +14220,15 @@ msgid "Invalid project path (changed anything?)." msgstr "Ðекоректний шлÑÑ… до проєкту (щоÑÑŒ змінилоÑÑ?)." #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." msgstr "" -"Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ project.godot у каталозі проєкту (помилка %d). " -"Можливо, файл вилучено або пошкоджено." +"Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ проєкт у '%s' (помилка %d). Можливо, файл вилучено " +"або пошкоджено." #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ проєкт у «%s»." +msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ проєкт у '%s' (помилка %d)." #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -15272,18 +15271,16 @@ msgid "Make Local" msgstr "Зробити локальним" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Enable Scene Unique Name(s)" -msgstr "Увімкнути унікальну назву Ñцени" +msgstr "Увімкнути Унікальні Ðазви Сцен(и)" #: editor/scene_tree_dock.cpp msgid "Unique names already used by another node in the scene:" msgstr "Цю унікальну назву у Ñцені вже викориÑтано іншим вузлом:" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Disable Scene Unique Name(s)" -msgstr "Вимкнути унікальна назва Ñцени" +msgstr "Вимкнути Унікальні Ðазви Сцен(и)" #: editor/scene_tree_dock.cpp msgid "New Scene Root" @@ -16315,7 +16312,7 @@ msgstr "Середовище" #: main/main.cpp msgid "Default Clear Color" -msgstr "Типовий колір очищеннÑ" +msgstr "Типовий чиÑтий колір" #: main/main.cpp msgid "Boot Splash" @@ -16848,12 +16845,10 @@ msgid "Sparse Indices Component Type" msgstr "Тип компонентів індекÑів розÑіюваннÑ" #: modules/gltf/gltf_accessor.cpp -#, fuzzy msgid "Sparse Values Buffer View" -msgstr "Буферне Ð¿Ð¾Ð´Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·Ñ€Ñ–Ð´Ð¶ÐµÐ½Ð¸Ñ… значень" +msgstr "ПереглÑд буфера розріджених значень" #: modules/gltf/gltf_accessor.cpp -#, fuzzy msgid "Sparse Values Byte Offset" msgstr "Ð—Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð±Ð°Ð¹Ñ‚Ñ–Ð² розріджених значень" @@ -16879,7 +16874,7 @@ msgstr "Розмір Ð¿Ð¾Ð»Ñ Ð·Ð¾Ñ€Ñƒ" #: modules/gltf/gltf_camera.cpp msgid "Zfar" -msgstr "" +msgstr "Ð’Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð¾ Z" #: modules/gltf/gltf_camera.cpp msgid "Znear" @@ -16982,20 +16977,22 @@ msgid "Joint I To Name" msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ I З Іменем" #: modules/gltf/gltf_skin.cpp +#, fuzzy msgid "Godot Skin" -msgstr "" +msgstr "Godot текÑтура" #: modules/gltf/gltf_spec_gloss.cpp msgid "Diffuse Img" -msgstr "" +msgstr "РозÑÑ–Ñне зображеннÑ" #: modules/gltf/gltf_spec_gloss.cpp msgid "Diffuse Factor" -msgstr "" +msgstr "Фактор розÑіюваннÑ" #: modules/gltf/gltf_spec_gloss.cpp +#, fuzzy msgid "Gloss Factor" -msgstr "" +msgstr "Фактор блиÑку" #: modules/gltf/gltf_spec_gloss.cpp msgid "Specular Factor" @@ -17003,7 +17000,7 @@ msgstr "Коефіцієнт дзеркальноÑÑ‚Ñ–" #: modules/gltf/gltf_spec_gloss.cpp msgid "Spec Gloss Img" -msgstr "" +msgstr "Дзеркальне глÑнцеве зображеннÑ" #: modules/gltf/gltf_state.cpp msgid "Json" @@ -17022,8 +17019,9 @@ msgid "GLB Data" msgstr "Дані GLB" #: modules/gltf/gltf_state.cpp +#, fuzzy msgid "Use Named Skin Binds" -msgstr "" +msgstr "ВикориÑтовуйте іменовані обшивки" #: modules/gltf/gltf_state.cpp msgid "Buffer Views" @@ -17127,7 +17125,7 @@ msgstr "ÐавігаціÑ" #: scene/3d/navigation_mesh_instance.cpp #, fuzzy msgid "Navigation Layers" -msgstr "Поведінка навігації" +msgstr "Ðавігаційні шари" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Next Plane" @@ -17292,19 +17290,19 @@ msgstr "Запікати карти оÑвітленнÑ" #: modules/lightmapper_cpu/register_types.cpp msgid "Low Quality Ray Count" -msgstr "" +msgstr "КількіÑÑ‚ÑŒ променів низької ÑкоÑÑ‚Ñ–" #: modules/lightmapper_cpu/register_types.cpp msgid "Medium Quality Ray Count" -msgstr "" +msgstr "Ð¡ÐµÑ€ÐµÐ´Ð½Ñ ÑкіÑÑ‚ÑŒ підрахунку променів" #: modules/lightmapper_cpu/register_types.cpp msgid "High Quality Ray Count" -msgstr "" +msgstr "ВиÑока ÑкіÑÑ‚ÑŒ підрахунку променів" #: modules/lightmapper_cpu/register_types.cpp msgid "Ultra Quality Ray Count" -msgstr "" +msgstr "КількіÑÑ‚ÑŒ променів виÑокої ÑкоÑÑ‚Ñ–" #: modules/minimp3/audio_stream_mp3.cpp #: modules/minimp3/resource_importer_mp3.cpp @@ -17315,7 +17313,7 @@ msgstr "Ð—Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ†Ð¸ÐºÐ»Ñƒ" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "Eye Height" -msgstr "" +msgstr "ВиÑота очей" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "IOD" @@ -17331,7 +17329,7 @@ msgstr "ПереглÑд без тіней" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "Oversample" -msgstr "" +msgstr "Ðадвибірка" #: modules/mobile_vr/mobile_vr_interface.cpp msgid "K1" @@ -17354,19 +17352,16 @@ msgid "Auto Update Project" msgstr "Проєкт без назви" #: modules/mono/godotsharp_dirs.cpp -#, fuzzy msgid "Assembly Name" -msgstr "Показана назва" +msgstr "Ðазва збірки" #: modules/mono/godotsharp_dirs.cpp -#, fuzzy msgid "Solution Directory" -msgstr "Виберіть каталог" +msgstr "Каталог проєкту" #: modules/mono/godotsharp_dirs.cpp -#, fuzzy msgid "C# Project Directory" -msgstr "Виберіть каталог" +msgstr "Каталог проєкту C#" #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" @@ -17516,8 +17511,9 @@ msgid "IGD Service Type" msgstr "Тип Ñлужби IGD" #: modules/upnp/upnp_device.cpp +#, fuzzy msgid "IGD Our Addr" -msgstr "" +msgstr "IGD це Ðаша адреÑа" #: modules/upnp/upnp_device.cpp msgid "IGD Status" @@ -18314,12 +18310,14 @@ msgid "Optional Features" msgstr "Ðеобов'Ñзкові можливоÑÑ‚Ñ–" #: modules/webxr/webxr_interface.cpp +#, fuzzy msgid "Requested Reference Space Types" -msgstr "" +msgstr "Запитані типи довідкового проÑтору" #: modules/webxr/webxr_interface.cpp +#, fuzzy msgid "Reference Space Type" -msgstr "" +msgstr "Довідка типу проÑтору" #: modules/webxr/webxr_interface.cpp msgid "Visibility State" @@ -18335,7 +18333,7 @@ msgstr "Стандартна прив'Ñзка XR" #: platform/android/export/export.cpp msgid "Android SDK Path" -msgstr "" +msgstr "ШлÑÑ… Android SDK" #: platform/android/export/export.cpp msgid "Debug Keystore" @@ -18358,8 +18356,9 @@ msgid "Shutdown ADB On Exit" msgstr "" #: platform/android/export/export_plugin.cpp +#, fuzzy msgid "Launcher Icons" -msgstr "" +msgstr "Значки панелі запуÑку" #: platform/android/export/export_plugin.cpp #, fuzzy @@ -18367,12 +18366,14 @@ msgid "Main 192 X 192" msgstr "iPhone 120 X 120" #: platform/android/export/export_plugin.cpp +#, fuzzy msgid "Adaptive Foreground 432 X 432" -msgstr "" +msgstr "адаптивний передній план 432 x 432" #: platform/android/export/export_plugin.cpp +#, fuzzy msgid "Adaptive Background 432 X 432" -msgstr "" +msgstr "адаптивний задній план(фон) 432 x 432" #: platform/android/export/export_plugin.cpp msgid "Package name is missing." @@ -18447,8 +18448,9 @@ msgid "Release Password" msgstr "Пароль випуÑку" #: platform/android/export/export_plugin.cpp +#, fuzzy msgid "One Click Deploy" -msgstr "" +msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð² один клік" #: platform/android/export/export_plugin.cpp msgid "Clear Previous Install" @@ -18729,10 +18731,13 @@ msgid "\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid." msgstr "" #: platform/android/export/export_plugin.cpp +#, fuzzy msgid "" "\"Min SDK\" cannot be lower than %d, which is the version needed by the " "Godot library." msgstr "" +"\"Min SDK\" не може бути нижчим за %d, що Ñ” верÑією, необхідною Ð´Ð»Ñ " +"бібліотеки Godot." #: platform/android/export/export_plugin.cpp #, fuzzy @@ -18743,15 +18748,20 @@ msgstr "" "збираннÑ»." #: platform/android/export/export_plugin.cpp +#, fuzzy msgid "" "\"Target SDK\" should be a valid integer, but got \"%s\" which is invalid." msgstr "" +"\"Target SDK\" має бути дійÑним цілим чиÑлом, але отримано \"%s\", Ñке не Ñ” " +"дійÑним." #: platform/android/export/export_plugin.cpp msgid "" "\"Target SDK\" %d is higher than the default version %d. This may work, but " "wasn't tested and may be unstable." msgstr "" +"\"Target SDK\" %d вищий за Ñтандартну верÑÑ–ÑŽ %d. Це може працювати, але це " +"не було перевірено та може бути неÑтабільним." #: platform/android/export/export_plugin.cpp #, fuzzy @@ -18930,8 +18940,9 @@ msgid "The character '%s' is not allowed in Identifier." msgstr "У назві ідентифікатора не можна викориÑтовувати Ñимволи «%s»." #: platform/iphone/export/export.cpp +#, fuzzy msgid "Landscape Launch Screens" -msgstr "" +msgstr "Ðльбомні екрани запуÑку" #: platform/iphone/export/export.cpp #, fuzzy @@ -18954,8 +18965,9 @@ msgid "iPad 2048 X 1536" msgstr "iPad 152 X 152" #: platform/iphone/export/export.cpp +#, fuzzy msgid "Portrait Launch Screens" -msgstr "" +msgstr "Портретні початкові екрани" #: platform/iphone/export/export.cpp #, fuzzy @@ -18994,15 +19006,16 @@ msgstr "iPhone 120 X 120" #: platform/iphone/export/export.cpp msgid "App Store Team ID" -msgstr "" +msgstr "Ідентифікатор команди App Store" #: platform/iphone/export/export.cpp +#, fuzzy msgid "Provisioning Profile UUID Debug" -msgstr "" +msgstr "ÐÐ°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽ UUID" #: platform/iphone/export/export.cpp msgid "Code Sign Identity Debug" -msgstr "" +msgstr "ÐÐ°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— коду" #: platform/iphone/export/export.cpp msgid "Export Method Debug" diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po index 1046f11996..bc15a001c9 100644 --- a/editor/translations/ur_PK.po +++ b/editor/translations/ur_PK.po @@ -10936,7 +10936,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/vi.po b/editor/translations/vi.po index b4a5f4494b..0ff37e659e 100644 --- a/editor/translations/vi.po +++ b/editor/translations/vi.po @@ -11119,7 +11119,7 @@ msgstr "Phối cảnh" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po index 52f072e946..5b58752f63 100644 --- a/editor/translations/zh_CN.po +++ b/editor/translations/zh_CN.po @@ -92,7 +92,7 @@ msgstr "" "Project-Id-Version: Chinese (Simplified) (Godot Engine)\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: 2018-01-20 12:15+0200\n" -"PO-Revision-Date: 2022-12-05 08:51+0000\n" +"PO-Revision-Date: 2022-12-28 00:54+0000\n" "Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n" "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hans/>\n" @@ -101,7 +101,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -145,15 +145,15 @@ msgstr "å±å¹•å¸¸äº®" #: core/bind/core_bind.cpp msgid "Min Window Size" -msgstr "最å°çª—å£å¤§å°" +msgstr "最å°çª—å£å°ºå¯¸" #: core/bind/core_bind.cpp msgid "Max Window Size" -msgstr "最大窗å£å¤§å°" +msgstr "最大窗å£å°ºå¯¸" #: core/bind/core_bind.cpp msgid "Screen Orientation" -msgstr "窗å£æœå‘" +msgstr "å±å¹•æœå‘" #: core/bind/core_bind.cpp core/project_settings.cpp main/main.cpp #: platform/uwp/os_uwp.cpp @@ -1097,7 +1097,7 @@ msgstr "æƒé‡é‡‡æ ·" #: drivers/gles3/rasterizer_scene_gles3.cpp msgid "Voxel Cone Tracing" -msgstr "ä½“ç´ æ¤Žè¿½è¸ª" +msgstr "ä½“ç´ é”¥è¿½è¸ª" #: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp msgid "High Quality" @@ -5843,7 +5843,7 @@ msgstr "骨骼轮廓颜色" #: editor/editor_settings.cpp msgid "Viewport Border Color" -msgstr "视区边框颜色" +msgstr "视å£è¾¹æ¡†é¢œè‰²" #: editor/editor_settings.cpp msgid "Constrain Editor View" @@ -8685,7 +8685,7 @@ msgid "" "Overrides the running project's camera with the editor viewport camera." msgstr "" "项目相机覆盖\n" -"使用编辑器视图相机覆盖æ£åœ¨è¿è¡Œçš„项目ä¸çš„相机。" +"使用编辑器视å£ç›¸æœºè¦†ç›–æ£åœ¨è¿è¡Œçš„项目ä¸çš„相机。" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -10819,7 +10819,7 @@ msgstr "é€è§†åŽè§†å›¾" msgid " [auto]" msgstr " [自动]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [å…¥å£ç”Ÿæ•ˆ]" @@ -11203,27 +11203,27 @@ msgstr "å˜æ¢å¯¹è¯æ¡†..." #: editor/plugins/spatial_editor_plugin.cpp msgid "1 Viewport" -msgstr "1 个视窗" +msgstr "1 个视å£" #: editor/plugins/spatial_editor_plugin.cpp msgid "2 Viewports" -msgstr "2 个视窗" +msgstr "2 个视å£" #: editor/plugins/spatial_editor_plugin.cpp msgid "2 Viewports (Alt)" -msgstr "2 个视窗(备选)" +msgstr "2 个视å£ï¼ˆå¤‡é€‰ï¼‰" #: editor/plugins/spatial_editor_plugin.cpp msgid "3 Viewports" -msgstr "3 个视窗" +msgstr "3 个视å£" #: editor/plugins/spatial_editor_plugin.cpp msgid "3 Viewports (Alt)" -msgstr "3 个视窗(备选)" +msgstr "3 个视å£ï¼ˆå¤‡é€‰ï¼‰" #: editor/plugins/spatial_editor_plugin.cpp msgid "4 Viewports" -msgstr "4 个视窗" +msgstr "4 个视å£" #: editor/plugins/spatial_editor_plugin.cpp msgid "Gizmos" @@ -11320,7 +11320,7 @@ msgstr "æ“作å°å·¥å…·ä¸é€æ˜Žåº¦" #: editor/plugins/spatial_editor_plugin.cpp msgid "Show Viewport Rotation Gizmo" -msgstr "显示视区旋转å°å·¥å…·" +msgstr "显示视å£æ—‹è½¬å°å·¥å…·" #: editor/plugins/spatial_editor_plugin.cpp msgid "Unnamed Gizmo" @@ -14010,16 +14010,13 @@ msgid "Invalid project path (changed anything?)." msgstr "é¡¹ç›®è·¯å¾„æ— æ•ˆï¼ˆè¢«å¤–éƒ¨ä¿®æ”¹ï¼Ÿï¼‰ã€‚" #: editor/project_manager.cpp -#, fuzzy msgid "" "Couldn't load project at '%s' (error %d). It may be missing or corrupted." -msgstr "" -"æ— æ³•åœ¨é¡¹ç›®è·¯å¾„ä¸åŠ è½½ project.godot 文件(错误 %d)。该文件å¯èƒ½ç¼ºå¤±æˆ–å·²æŸå。" +msgstr "æ— æ³•åŠ è½½ä½äºŽâ€œ%sâ€çš„项目(错误 %d)。项目å¯èƒ½ç¼ºå¤±æˆ–å·²æŸå。" #: editor/project_manager.cpp -#, fuzzy msgid "Couldn't save project at '%s' (error %d)." -msgstr "æ— æ³•æ‰“å¼€ä½äºŽâ€œ%sâ€çš„项目。" +msgstr "æ— æ³•ä¿å˜ä½äºŽâ€œ%sâ€çš„项目(错误 %d)。" #: editor/project_manager.cpp msgid "Couldn't create project.godot in project path." @@ -14934,7 +14931,7 @@ msgstr "å°†èŠ‚ç‚¹è®¾ç½®ä¸ºæ ¹èŠ‚ç‚¹" #: editor/scene_tree_dock.cpp msgid "Delete %d nodes and any children?" -msgstr "是å¦åˆ 除节点 “%s†åŠå…¶å节点?" +msgstr "是å¦åˆ 除 %d 个节点åŠå…¶å节点?" #: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" @@ -19971,7 +19968,7 @@ msgstr "缩放" #: scene/2d/camera_2d.cpp scene/main/canvas_layer.cpp msgid "Custom Viewport" -msgstr "自定义视区" +msgstr "自定义视å£" #: scene/2d/camera_2d.cpp scene/3d/camera.cpp scene/3d/interpolated_camera.cpp #: scene/animation/animation_player.cpp scene/animation/animation_tree.cpp @@ -22699,14 +22696,12 @@ msgid "AABB" msgstr "AABB" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Sorting" msgstr "排åº" #: scene/3d/visual_instance.cpp -#, fuzzy msgid "Use AABB Center" -msgstr "使用环境光" +msgstr "使用 AABB ä¸å¿ƒ" #: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp msgid "Geometry" @@ -23869,7 +23864,7 @@ msgstr "拉伸收缩" #: scene/main/canvas_layer.cpp msgid "Follow Viewport" -msgstr "è·Ÿéšè§†åŒº" +msgstr "è·Ÿéšè§†å£" #: scene/main/http_request.cpp msgid "Download File" diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po index 8af64cfc4e..80c7658ff9 100644 --- a/editor/translations/zh_HK.po +++ b/editor/translations/zh_HK.po @@ -11433,7 +11433,7 @@ msgstr "" msgid " [auto]" msgstr "" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr "" diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po index dd54885310..4d04c45976 100644 --- a/editor/translations/zh_TW.po +++ b/editor/translations/zh_TW.po @@ -38,13 +38,14 @@ # Shi-Xun Hong <jimmy3421@gmail.com>, 2022. # Hugel <qihu@nfschina.com>, 2022. # nitenook <admin@alterbaum.net>, 2022. +# Edison Lee <edisonlee@edisonlee55.com>, 2023. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-10-16 07:25+0000\n" -"Last-Translator: BinotaLIU <me@binota.org>\n" +"PO-Revision-Date: 2023-01-14 10:06+0000\n" +"Last-Translator: Edison Lee <edisonlee@edisonlee55.com>\n" "Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hant/>\n" "Language: zh_TW\n" @@ -52,7 +53,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.15-dev\n" +"X-Generator: Weblate 4.15.1-dev\n" #: core/bind/core_bind.cpp main/main.cpp msgid "Tablet Driver" @@ -1154,7 +1155,7 @@ msgstr "旋轉" #: editor/animation_track_editor.cpp editor/script_editor_debugger.cpp #: modules/visual_script/visual_script_nodes.cpp scene/gui/range.cpp msgid "Value" -msgstr "數值" +msgstr "值" #: editor/animation_track_editor.cpp msgid "Arg Count" @@ -10771,7 +10772,7 @@ msgstr "é€è¦–後視圖" msgid " [auto]" msgstr " [自動]" -#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled. +#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled. #: editor/plugins/spatial_editor_plugin.cpp msgid " [portals active]" msgstr " [å…¥å£ç”Ÿæ•ˆ]" @@ -17787,9 +17788,8 @@ msgid "ShiftRight %s" msgstr "å°‡ %s å‘å³ç§»å‹•" #: modules/visual_script/visual_script_func_nodes.cpp -#, fuzzy msgid "BitAnd %s" -msgstr "新增 %" +msgstr "" #: modules/visual_script/visual_script_func_nodes.cpp #, fuzzy @@ -18557,9 +18557,8 @@ msgstr "「Target Sdkã€ç‰ˆæœ¬å¿…é ˆé«˜æ–¼æˆ–äºŽã€ŒMin Sdkã€ç‰ˆæœ¬ä¸€è‡´ã€‚" #: platform/android/export/export_plugin.cpp platform/osx/export/export.cpp #: platform/windows/export/export.cpp -#, fuzzy msgid "Code Signing" -msgstr "訊號" +msgstr "程å¼ç¢¼ç°½ç« " #: platform/android/export/export_plugin.cpp msgid "" @@ -18766,11 +18765,11 @@ msgstr "" #: platform/iphone/export/export.cpp msgid "App Store Team ID" -msgstr "" +msgstr "App Store 團隊 ID" #: platform/iphone/export/export.cpp msgid "Provisioning Profile UUID Debug" -msgstr "" +msgstr "部署æ述檔 UUID åµéŒ¯" #: platform/iphone/export/export.cpp msgid "Code Sign Identity Debug" @@ -18848,19 +18847,16 @@ msgid "Accessible From iTunes Sharing" msgstr "" #: platform/iphone/export/export.cpp platform/osx/export/export.cpp -#, fuzzy msgid "Privacy" -msgstr "實體按éµ" +msgstr "éš±ç§" #: platform/iphone/export/export.cpp platform/osx/export/export.cpp -#, fuzzy msgid "Camera Usage Description" -msgstr "說明" +msgstr "相機使用æè¿°" #: platform/iphone/export/export.cpp platform/osx/export/export.cpp -#, fuzzy msgid "Microphone Usage Description" -msgstr "屬性說明" +msgstr "麥克風使用æè¿°" #: platform/iphone/export/export.cpp #, fuzzy @@ -18933,9 +18929,8 @@ msgid "Custom BG Color" msgstr "剪下節點" #: platform/iphone/export/export.cpp -#, fuzzy msgid "Export Icons" -msgstr "展開全部" +msgstr "匯出圖示" #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp #: platform/osx/export/export.cpp @@ -19017,7 +19012,7 @@ msgstr "" #: platform/javascript/export/export.cpp msgid "HTML" -msgstr "" +msgstr "HTML" #: platform/javascript/export/export.cpp #, fuzzy @@ -19052,7 +19047,7 @@ msgstr "" #: platform/javascript/export/export.cpp msgid "Offline Page" -msgstr "" +msgstr "離線é é¢" #: platform/javascript/export/export.cpp msgid "Icon 144 X 144" @@ -19084,16 +19079,15 @@ msgstr "" #: platform/javascript/export/export.cpp msgid "HTTP Host" -msgstr "" +msgstr "HTTP 主機" #: platform/javascript/export/export.cpp msgid "HTTP Port" -msgstr "" +msgstr "HTTP é€£æŽ¥åŸ " #: platform/javascript/export/export.cpp -#, fuzzy msgid "Use SSL" -msgstr "使用å¸é™„" +msgstr "使用 SSL" #: platform/javascript/export/export.cpp msgid "SSL Key" @@ -19159,9 +19153,8 @@ msgid "Invalid entitlements file." msgstr "無效的副檔å。" #: platform/osx/export/codesign.cpp -#, fuzzy msgid "Invalid executable file." -msgstr "無效的副檔å。" +msgstr "無效的執行檔。" #: platform/osx/export/codesign.cpp msgid "Can't resize signature load command." @@ -19229,24 +19222,21 @@ msgid "Removable Volumes Usage Description" msgstr "" #: platform/osx/export/export.cpp platform/windows/export/export.cpp -#, fuzzy msgid "Codesign" -msgstr "節點" +msgstr "程å¼ç¢¼ç°½ç« " #: platform/osx/export/export.cpp platform/uwp/export/export.cpp #: platform/windows/export/export.cpp -#, fuzzy msgid "Identity" -msgstr "å‘左縮排" +msgstr "身分" #: platform/osx/export/export.cpp platform/windows/export/export.cpp -#, fuzzy msgid "Timestamp" -msgstr "時間" +msgstr "時間戳" #: platform/osx/export/export.cpp msgid "Hardened Runtime" -msgstr "" +msgstr "Hardened Runtime" #: platform/osx/export/export.cpp #, fuzzy @@ -19259,9 +19249,8 @@ msgid "Entitlements" msgstr "Gizmo" #: platform/osx/export/export.cpp -#, fuzzy msgid "Custom File" -msgstr "剪下節點" +msgstr "自訂檔案" #: platform/osx/export/export.cpp msgid "Allow JIT Code Execution" @@ -19281,75 +19270,64 @@ msgid "Disable Library Validation" msgstr "å·²åœç”¨çš„按鈕" #: platform/osx/export/export.cpp -#, fuzzy msgid "Audio Input" -msgstr "新增輸入" +msgstr "音æºè¼¸å…¥" #: platform/osx/export/export.cpp msgid "Address Book" -msgstr "" +msgstr "地å€ç°¿" #: platform/osx/export/export.cpp msgid "Calendars" -msgstr "" +msgstr "日曆" #: platform/osx/export/export.cpp -#, fuzzy msgid "Photos Library" -msgstr "匯出函å¼åº«" +msgstr "照片圖庫" #: platform/osx/export/export.cpp -#, fuzzy msgid "Apple Events" -msgstr "新增事件" +msgstr "Apple 活動" #: platform/osx/export/export.cpp -#, fuzzy msgid "Debugging" msgstr "åµéŒ¯" #: platform/osx/export/export.cpp msgid "App Sandbox" -msgstr "" +msgstr "應用程å¼æ²™ç›’" #: platform/osx/export/export.cpp -#, fuzzy msgid "Network Server" -msgstr "網路分æžå·¥å…·" +msgstr "網路伺æœå™¨" #: platform/osx/export/export.cpp -#, fuzzy msgid "Network Client" -msgstr "網路分æžå·¥å…·" +msgstr "網路客戶端" #: platform/osx/export/export.cpp -#, fuzzy msgid "Device USB" -msgstr "è£ç½®" +msgstr "è£ç½® USB" #: platform/osx/export/export.cpp msgid "Device Bluetooth" -msgstr "" +msgstr "è£ç½®è—芽" #: platform/osx/export/export.cpp -#, fuzzy msgid "Files Downloads" -msgstr "下載" +msgstr "檔案下載" #: platform/osx/export/export.cpp -#, fuzzy msgid "Files Pictures" -msgstr "功能" +msgstr "檔案圖片" #: platform/osx/export/export.cpp -#, fuzzy msgid "Files Music" -msgstr "檔案" +msgstr "檔案音樂" #: platform/osx/export/export.cpp -#, fuzzy msgid "Files Movies" -msgstr "篩é¸åœ–å¡Š" +msgstr "檔案影片" #: platform/osx/export/export.cpp platform/windows/export/export.cpp #, fuzzy @@ -19362,15 +19340,15 @@ msgstr "å…¬è‰" #: platform/osx/export/export.cpp msgid "Apple ID Name" -msgstr "" +msgstr "Apple ID å稱" #: platform/osx/export/export.cpp msgid "Apple ID Password" -msgstr "" +msgstr "Apple ID 密碼" #: platform/osx/export/export.cpp msgid "Apple Team ID" -msgstr "" +msgstr "Apple 團隊 ID" #: platform/osx/export/export.cpp msgid "Could not open icon file \"%s\"." @@ -20004,7 +19982,7 @@ msgstr "" #: platform/windows/export/export.cpp msgid "Wine" -msgstr "" +msgstr "Wine" #: platform/x11/export/export.cpp msgid "32-bit executables cannot have embedded data >= 4 GiB." @@ -27006,7 +26984,7 @@ msgstr "æ··åˆ (Mix)" #: servers/audio/effects/audio_effect_compressor.cpp msgid "Sidechain" -msgstr "" +msgstr "å´éˆ" #: servers/audio/effects/audio_effect_delay.cpp msgid "Tap 1" diff --git a/main/main.cpp b/main/main.cpp index 7ba5ffab2a..cfde124b90 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -185,6 +185,7 @@ static bool init_maximized = false; static bool init_windowed = false; static bool init_always_on_top = false; static bool init_use_custom_pos = false; +static bool init_use_custom_screen = false; static Vector2 init_custom_pos; // Debug @@ -964,6 +965,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (I->next()) { init_screen = I->next()->get().to_int(); + init_use_custom_screen = true; N = I->next()->next(); } else { @@ -1669,7 +1671,23 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT; } window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int()); - init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int(); + int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int(); + if (initial_position_type == 0) { + if (!init_use_custom_pos) { + init_custom_pos = GLOBAL_GET("display/window/size/initial_position").operator Vector2i(); + init_use_custom_pos = true; + } + } else if (initial_position_type == 1) { + if (!init_use_custom_screen) { + init_screen = DisplayServer::SCREEN_PRIMARY; + init_use_custom_screen = true; + } + } else if (initial_position_type == 2) { + if (!init_use_custom_screen) { + init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int(); + init_use_custom_screen = true; + } + } } GLOBAL_DEF("internationalization/locale/include_text_server_data", false); @@ -1677,10 +1695,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true); OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false); +#ifdef TOOLS_ENABLED if (editor || project_manager) { - // The editor and project manager always detect and use hiDPI if needed + // The editor and project manager always detect and use hiDPI if needed. OS::get_singleton()->_allow_hidpi = true; + // Disable Vulkan overlays in editor, they cause various issues. + OS::get_singleton()->set_environment("DISABLE_MANGOHUD", "1"); // GH-57403. + OS::get_singleton()->set_environment("DISABLE_RTSS_LAYER", "1"); // GH-57937. + OS::get_singleton()->set_environment("DISABLE_VKBASALT", "1"); + } else { + // Re-allow using Vulkan overlays, disabled while using the editor. + OS::get_singleton()->unset_environment("DISABLE_MANGOHUD"); + OS::get_singleton()->unset_environment("DISABLE_RTSS_LAYER"); + OS::get_singleton()->unset_environment("DISABLE_VKBASALT"); } +#endif if (rtm == -1) { rtm = GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE); @@ -2114,7 +2143,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { #endif } -#ifdef TOOLS_ENABLED +#if defined(TOOLS_ENABLED) && defined(MACOS_ENABLED) if (OS::get_singleton()->get_bundle_icon_path().is_empty()) { Ref<Image> icon = memnew(Image(app_icon_png)); DisplayServer::get_singleton()->set_icon(icon); @@ -2136,7 +2165,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { if (id) { agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false); - if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && + if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) { if (!DisplayServer::get_singleton()->is_touchscreen_available()) { //only if no touchscreen ui hint, set emulation @@ -2144,7 +2173,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { } } - id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF("input_devices/pointing/emulate_mouse_from_touch", true))); + id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true))); } MAIN_PRINT("Main: Load Translations and Remaps"); @@ -2420,6 +2449,14 @@ bool Main::start() { ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path."); } +#ifndef MODULE_MONO_ENABLED + // Hack to define .NET-specific project settings even on non-.NET builds, + // so that we don't lose their descriptions and default values in DocTools. + // Default values should be synced with mono_gd/gd_mono.cpp. + GLOBAL_DEF("dotnet/project/assembly_name", ""); + GLOBAL_DEF("dotnet/project/solution_directory", ""); +#endif + Error err; DocTools doc; doc.generate(doc_base); @@ -3030,6 +3067,9 @@ bool Main::iteration() { PhysicsServer2D::get_singleton()->flush_queries(); if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) { + PhysicsServer3D::get_singleton()->end_sync(); + PhysicsServer2D::get_singleton()->end_sync(); + exit = true; break; } @@ -3153,10 +3193,12 @@ bool Main::iteration() { auto_build_solutions = false; // Only relevant when running the editor. if (!editor) { + OS::get_singleton()->set_exit_code(EXIT_FAILURE); ERR_FAIL_V_MSG(true, "Command line option --build-solutions was passed, but no project is being edited. Aborting."); } if (!EditorNode::get_singleton()->call_build()) { + OS::get_singleton()->set_exit_code(EXIT_FAILURE); ERR_FAIL_V_MSG(true, "Command line option --build-solutions was passed, but the build callback failed. Aborting."); } diff --git a/misc/hooks/asmessage.applescript b/misc/hooks/asmessage.applescript new file mode 100644 index 0000000000..15ba94dc37 --- /dev/null +++ b/misc/hooks/asmessage.applescript @@ -0,0 +1,59 @@ +on run argv + set vButtons to { "OK" } + set vButtonCodes to { 0 } + set vDbutton to "OK" + set vText to "" + set vTitle to "" + set vTimeout to -1 + + repeat with i from 1 to length of argv + try + set vArg to item i of argv + if vArg = "-buttons" then + set vButtonsAndCodes to my fSplit(item (i + 1) of argv, ",") + set vButtons to {} + set vButtonCodes to {} + repeat with j from 1 to length of vButtonsAndCodes + set vBtn to my fSplit(item j of vButtonsAndCodes, ":") + copy (item 1 of vBtn) to the end of the vButtons + copy (item 2 of vBtn) to the end of the vButtonCodes + end repeat + else if vArg = "-title" then + set vTitle to item (i + 1) of argv + else if vArg = "-center" then + -- not supported + else if vArg = "-default" then + set vDbutton to item (i + 1) of argv + else if vArg = "-geometry" then + -- not supported + else if vArg = "-nearmouse" then + -- not supported + else if vArg = "-timeout" then + set vTimeout to item (i + 1) of argv as integer + else if vArg = "-file" then + set vText to read (item (i + 1) of argv) as string + else if vArg = "-text" then + set vText to item (i + 1) of argv + end if + end try + end repeat + + set vDlg to display dialog vText buttons vButtons default button vDbutton with title vTitle giving up after vTimeout with icon stop + set vRet to button returned of vDlg + repeat with i from 1 to length of vButtons + set vBtn to item i of vButtons + if vBtn = vRet + return item i of vButtonCodes + end if + end repeat + + return 0 +end run + +on fSplit(vString, vDelimiter) + set oldDelimiters to AppleScript's text item delimiters + set AppleScript's text item delimiters to vDelimiter + set vArray to every text item of vString + set AppleScript's text item delimiters to oldDelimiters + return vArray +end fSplit diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black index b7335685ae..bbad6a690a 100755 --- a/misc/hooks/pre-commit-black +++ b/misc/hooks/pre-commit-black @@ -34,6 +34,9 @@ XMSG=`which xmessage 2>/dev/null` # Path to powershell (Windows only) PWSH=`which powershell 2>/dev/null` +# Path to osascript (macOS only) +OSA=`which osascript 2>/dev/null` + ################################################################## # There should be no need to change anything below this line. @@ -69,6 +72,10 @@ if [ ! -x "$BLACK" ] ; then elif [ -x "$XMSG" ] ; then $XMSG -center -title "Error" "Error: black executable not found." exit 1 + elif [ -x "$OSA" ] ; then + asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" + $OSA "$asmessage" -center -title "Error" --text "Error: black executable not found." + exit 1 elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found." @@ -159,6 +166,16 @@ while true; do else yn="N" fi + elif [ -x "$OSA" ] ; then + asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" + choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"` + if [ "$choice" = "100" ] ; then + yn="Y" + elif [ "$choice" = "200" ] ; then + yn="S" + else + yn="N" + fi elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" @@ -171,7 +188,7 @@ while true; do yn="N" fi else - printf "Error: zenity, xmessage, or powershell executable not found.\n" + printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n" exit 1 fi else diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format index 9570d5120b..fd0213c175 100755 --- a/misc/hooks/pre-commit-clang-format +++ b/misc/hooks/pre-commit-clang-format @@ -47,6 +47,9 @@ XMSG=`which xmessage 2>/dev/null` # Path to powershell (Windows only) PWSH=`which powershell 2>/dev/null` +# Path to osascript (macOS only) +OSA=`which osascript 2>/dev/null` + ################################################################## # There should be no need to change anything below this line. @@ -89,6 +92,10 @@ if [ ! -x "$CLANG_FORMAT" ] ; then elif [ -x "$XMSG" ] ; then $XMSG -center -title "Error" "$message" exit 1 + elif [ -x "$OSA" ] ; then + asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" + $OSA "$asmessage" -center -title "Error" --text "$message" + exit 1 elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message" @@ -199,6 +206,16 @@ while true; do else yn="N" fi + elif [ -x "$OSA" ] ; then + asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" + choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"` + if [ "$choice" = "100" ] ; then + yn="Y" + elif [ "$choice" = "200" ] ; then + yn="S" + else + yn="N" + fi elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" @@ -211,7 +228,7 @@ while true; do yn="N" fi else - printf "Error: zenity, xmessage, or powershell executable not found.\n" + printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n" exit 1 fi else diff --git a/misc/scripts/codespell.sh b/misc/scripts/codespell.sh index c00d897666..34885016b6 100755 --- a/misc/scripts/codespell.sh +++ b/misc/scripts/codespell.sh @@ -1,5 +1,5 @@ #!/bin/sh -SKIP_LIST="./.git,./bin,./thirdparty,*.gen.*,*.po,*.pot,package-lock.json,./core/string/locales.h,./DONORS.md,./misc/dist/linux/org.godotengine.Godot.desktop,./misc/scripts/codespell.sh" +SKIP_LIST="./.*,./bin,.platform/web/node_modules,./platform/android/java/lib/src/com,./thirdparty,*.gen.*,*.po,*.pot,*.rc,package-lock.json,./core/string/locales.h,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./misc/dist/linux/org.godotengine.Godot.desktop,./misc/scripts/codespell.sh" IGNORE_LIST="alo,ba,childs,complies,curvelinear,doubleclick,expct,fave,findn,gird,gud,inout,lod,nd,numer,ois,readded,ro,sav,statics,te,varius,varn,wan" -codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}" +codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}" --builtin "clear,rare,en-GB_to_en-US" diff --git a/modules/astcenc/SCsub b/modules/astcenc/SCsub new file mode 100644 index 0000000000..0f04f2bc28 --- /dev/null +++ b/modules/astcenc/SCsub @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_astcenc = env_modules.Clone() + +# Thirdparty source files + +thirdparty_obj = [] + +thirdparty_dir = "#thirdparty/astcenc/" +thirdparty_sources = [ + "astcenc_averages_and_directions.cpp", + "astcenc_block_sizes.cpp", + "astcenc_color_quantize.cpp", + "astcenc_color_unquantize.cpp", + "astcenc_compress_symbolic.cpp", + "astcenc_compute_variance.cpp", + "astcenc_decompress_symbolic.cpp", + "astcenc_diagnostic_trace.cpp", + "astcenc_entry.cpp", + "astcenc_find_best_partitioning.cpp", + "astcenc_ideal_endpoints_and_weights.cpp", + "astcenc_image.cpp", + "astcenc_integer_sequence.cpp", + "astcenc_mathlib.cpp", + "astcenc_mathlib_softfloat.cpp", + "astcenc_partition_tables.cpp", + "astcenc_percentile_tables.cpp", + "astcenc_pick_best_endpoint_format.cpp", + "astcenc_platform_isa_detection.cpp", + "astcenc_quantization.cpp", + "astcenc_symbolic_physical.cpp", + "astcenc_weight_align.cpp", + "astcenc_weight_quant_xfer_tables.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_astcenc.Prepend(CPPPATH=[thirdparty_dir]) + +env_thirdparty = env_astcenc.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) +env.modules_sources += thirdparty_obj + +# Godot source files + +module_obj = [] + +env_astcenc.add_source_files(module_obj, "*.cpp") +env.modules_sources += module_obj + +# Needed to force rebuilding the module files when the thirdparty library is updated. +env.Depends(module_obj, thirdparty_obj) diff --git a/modules/astcenc/config.py b/modules/astcenc/config.py new file mode 100644 index 0000000000..eb565b85b9 --- /dev/null +++ b/modules/astcenc/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return env.editor_build + + +def configure(env): + pass diff --git a/modules/astcenc/image_compress_astcenc.cpp b/modules/astcenc/image_compress_astcenc.cpp new file mode 100644 index 0000000000..ce10201343 --- /dev/null +++ b/modules/astcenc/image_compress_astcenc.cpp @@ -0,0 +1,251 @@ +/**************************************************************************/ +/* image_compress_astcenc.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "image_compress_astcenc.h" + +#include "core/os/os.h" +#include "core/string/print_string.h" + +#include <astcenc.h> + +void _compress_astc(Image *r_img, float p_lossy_quality, Image::ASTCFormat p_format) { + uint64_t start_time = OS::get_singleton()->get_ticks_msec(); + + // TODO: See how to handle lossy quality. + + Image::Format img_format = r_img->get_format(); + if (img_format >= Image::FORMAT_DXT1) { + return; // Do not compress, already compressed. + } + + bool is_hdr = false; + if ((img_format >= Image::FORMAT_RH) && (img_format <= Image::FORMAT_RGBE9995)) { + is_hdr = true; + r_img->convert(Image::FORMAT_RGBAF); + } else { + r_img->convert(Image::FORMAT_RGBA8); + } + + // Determine encoder output format from our enum. + + Image::Format target_format = Image::FORMAT_RGBA8; + astcenc_profile profile = ASTCENC_PRF_LDR; + unsigned int block_x = 4; + unsigned int block_y = 4; + + if (p_format == Image::ASTCFormat::ASTC_FORMAT_4x4) { + if (is_hdr) { + target_format = Image::FORMAT_ASTC_4x4_HDR; + profile = ASTCENC_PRF_HDR; + } else { + target_format = Image::FORMAT_ASTC_4x4; + } + } else if (p_format == Image::ASTCFormat::ASTC_FORMAT_8x8) { + if (is_hdr) { + target_format = Image::FORMAT_ASTC_8x8_HDR; + profile = ASTCENC_PRF_HDR; + } else { + target_format = Image::FORMAT_ASTC_8x8; + } + block_x = 8; + block_y = 8; + } + + // Compress image data and (if required) mipmaps. + + const bool mipmaps = r_img->has_mipmaps(); + int width = r_img->get_width(); + int height = r_img->get_height(); + + print_verbose(vformat("astcenc: Encoding image size %dx%d to format %s%s.", width, height, Image::get_format_name(target_format), mipmaps ? ", with mipmaps" : "")); + + // Initialize astcenc. + + astcenc_config config; + config.block_x = block_x; + config.block_y = block_y; + config.profile = profile; + const float quality = ASTCENC_PRE_MEDIUM; + + astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_x, quality, 0, &config); + ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS, + vformat("astcenc: Configuration initialization failed: %s.", astcenc_get_error_string(status))); + + // Context allocation. + + astcenc_context *context; + const unsigned int thread_count = OS::get_singleton()->get_processor_count(); + + status = astcenc_context_alloc(&config, thread_count, &context); + ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS, + vformat("astcenc: Context allocation failed: %s.", astcenc_get_error_string(status))); + + // Compress image. + + Vector<uint8_t> image_data = r_img->get_data(); + uint8_t *slices = image_data.ptrw(); + + astcenc_image image; + image.dim_x = width; + image.dim_y = height; + image.dim_z = 1; + image.data_type = ASTCENC_TYPE_U8; + if (is_hdr) { + image.data_type = ASTCENC_TYPE_F32; + } + image.data = reinterpret_cast<void **>(&slices); + + // Compute the number of ASTC blocks in each dimension. + unsigned int block_count_x = (width + block_x - 1) / block_x; + unsigned int block_count_y = (height + block_y - 1) / block_y; + size_t comp_len = block_count_x * block_count_y * 16; + + Vector<uint8_t> compressed_data; + compressed_data.resize(comp_len); + compressed_data.fill(0); + + const astcenc_swizzle swizzle = { + ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A + }; + + status = astcenc_compress_image(context, &image, &swizzle, compressed_data.ptrw(), comp_len, 0); + ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS, + vformat("astcenc: ASTC image compression failed: %s.", astcenc_get_error_string(status))); + + // Replace original image with compressed one. + + r_img->set_data(width, height, mipmaps, target_format, compressed_data); + + print_verbose(vformat("astcenc: Encoding took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time))); +} + +void _decompress_astc(Image *r_img) { + uint64_t start_time = OS::get_singleton()->get_ticks_msec(); + + // Determine decompression parameters from image format. + + Image::Format img_format = r_img->get_format(); + bool is_hdr = false; + unsigned int block_x = 0; + unsigned int block_y = 0; + if (img_format == Image::FORMAT_ASTC_4x4) { + block_x = 4; + block_y = 4; + is_hdr = false; + } else if (img_format == Image::FORMAT_ASTC_4x4_HDR) { + block_x = 4; + block_y = 4; + is_hdr = true; + } else if (img_format == Image::FORMAT_ASTC_8x8) { + block_x = 8; + block_y = 8; + is_hdr = false; + } else if (img_format == Image::FORMAT_ASTC_8x8_HDR) { + block_x = 8; + block_y = 8; + is_hdr = true; + } else { + ERR_FAIL_MSG("astcenc: Cannot decompress Image with a non-ASTC format."); + } + + // Initialize astcenc. + + astcenc_profile profile = ASTCENC_PRF_LDR; + if (is_hdr) { + profile = ASTCENC_PRF_HDR; + } + astcenc_config config; + const float quality = ASTCENC_PRE_MEDIUM; + + astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_x, quality, 0, &config); + ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS, + vformat("astcenc: Configuration initialization failed: %s.", astcenc_get_error_string(status))); + + // Context allocation. + + astcenc_context *context = nullptr; + const unsigned int thread_count = OS::get_singleton()->get_processor_count(); + + status = astcenc_context_alloc(&config, thread_count, &context); + ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS, + vformat("astcenc: Context allocation failed: %s.", astcenc_get_error_string(status))); + + // Decompress image. + + const bool mipmaps = r_img->has_mipmaps(); + int width = r_img->get_width(); + int height = r_img->get_height(); + + astcenc_image image; + image.dim_x = width; + image.dim_y = height; + image.dim_z = 1; + image.data_type = ASTCENC_TYPE_U8; + Image::Format target_format = Image::FORMAT_RGBA8; + if (is_hdr) { + target_format = Image::FORMAT_RGBAF; + image.data_type = ASTCENC_TYPE_F32; + } + + Vector<uint8_t> image_data = r_img->get_data(); + + Vector<uint8_t> new_image_data; + new_image_data.resize(Image::get_image_data_size(width, height, target_format, false)); + new_image_data.fill(0); + uint8_t *slices = new_image_data.ptrw(); + image.data = reinterpret_cast<void **>(&slices); + + const astcenc_swizzle swizzle = { + ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A + }; + + status = astcenc_decompress_image(context, image_data.ptr(), image_data.size(), &image, &swizzle, 0); + ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS, + vformat("astcenc: ASTC decompression failed: %s.", astcenc_get_error_string(status))); + ERR_FAIL_COND_MSG(image.dim_z > 1, + "astcenc: ASTC decompression failed because this is a 3D texture, which is not supported."); + + // Replace original image with compressed one. + + Image::Format image_format = Image::FORMAT_RGBA8; + if (image.data_type == ASTCENC_TYPE_F32) { + image_format = Image::FORMAT_RGBAF; + } else if (image.data_type == ASTCENC_TYPE_U8) { + image_format = Image::FORMAT_RGBA8; + } else if (image.data_type == ASTCENC_TYPE_F16) { + image_format = Image::FORMAT_RGBAH; + } else { + ERR_FAIL_MSG("astcenc: ASTC decompression failed with an unknown format."); + } + + r_img->set_data(image.dim_x, image.dim_y, mipmaps, image_format, new_image_data); + + print_verbose(vformat("astcenc: Decompression took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time))); +} diff --git a/editor/array_property_edit.h b/modules/astcenc/image_compress_astcenc.h index 6e34a06943..a197a91e0d 100644 --- a/editor/array_property_edit.h +++ b/modules/astcenc/image_compress_astcenc.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* array_property_edit.h */ +/* image_compress_astcenc.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,42 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ARRAY_PROPERTY_EDIT_H -#define ARRAY_PROPERTY_EDIT_H +#ifndef IMAGE_COMPRESS_ASTCENC_H +#define IMAGE_COMPRESS_ASTCENC_H -#include "scene/main/node.h" +#include "core/io/image.h" -class ArrayPropertyEdit : public RefCounted { - GDCLASS(ArrayPropertyEdit, RefCounted); +void _compress_astc(Image *r_img, float p_lossy_quality, Image::ASTCFormat p_format); +void _decompress_astc(Image *r_img); - int page; - ObjectID obj; - StringName property; - String vtypes; - String subtype_hint_string; - PropertyHint subtype_hint; - Variant::Type subtype; - Variant get_array() const; - Variant::Type default_type; - - void _notif_change(); - void _set_size(int p_size); - void _set_value(int p_idx, const Variant &p_value); - - bool _dont_undo_redo(); - -protected: - static void _bind_methods(); - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - -public: - void edit(Object *p_obj, const StringName &p_prop, const String &p_hint_string, Variant::Type p_deftype); - - Node *get_node(); - - ArrayPropertyEdit(); -}; - -#endif // ARRAY_PROPERTY_EDIT_H +#endif // IMAGE_COMPRESS_ASTCENC_H diff --git a/editor/dictionary_property_edit.h b/modules/astcenc/register_types.cpp index 197bb394d4..0bb1c3432f 100644 --- a/editor/dictionary_property_edit.h +++ b/modules/astcenc/register_types.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* dictionary_property_edit.h */ +/* register_types.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,37 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DICTIONARY_PROPERTY_EDIT_H -#define DICTIONARY_PROPERTY_EDIT_H +#include "register_types.h" -#include "scene/main/node.h" +#include "image_compress_astcenc.h" -class DictionaryPropertyEdit : public RefCounted { - GDCLASS(DictionaryPropertyEdit, RefCounted); +void initialize_astcenc_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } - ObjectID obj; - StringName property; + Image::_image_compress_astc_func = _compress_astc; + Image::_image_decompress_astc = _decompress_astc; +} - void _notif_change(); - void _set_key(const Variant &p_old_key, const Variant &p_new_key); - void _set_value(const Variant &p_key, const Variant &p_value); - - Variant get_dictionary() const; - - bool _dont_undo_redo(); - -protected: - static void _bind_methods(); - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - -public: - void edit(Object *p_obj, const StringName &p_prop); - - Node *get_node(); - - DictionaryPropertyEdit(); -}; - -#endif // DICTIONARY_PROPERTY_EDIT_H +void uninitialize_astcenc_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} diff --git a/modules/astcenc/register_types.h b/modules/astcenc/register_types.h new file mode 100644 index 0000000000..636da9ff8b --- /dev/null +++ b/modules/astcenc/register_types.h @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* register_types.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef ASTCENC_REGISTER_TYPES_H +#define ASTCENC_REGISTER_TYPES_H + +#include "modules/register_module_types.h" + +void initialize_astcenc_module(ModuleInitializationLevel p_level); +void uninitialize_astcenc_module(ModuleInitializationLevel p_level); + +#endif // ASTCENC_REGISTER_TYPES_H diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index 3b789a235f..5b451fbf6b 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -58,6 +58,13 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, ERR_FAIL_COND_V_MSG(height % 8 != 0, ERR_UNAVAILABLE, vformat("1-bpp BMP images must have a height that is a multiple of 8, but the imported BMP is %d pixels tall.", int(height))); + } else if (bits_per_pixel == 2) { + // Requires bit unpacking... + ERR_FAIL_COND_V_MSG(width % 4 != 0, ERR_UNAVAILABLE, + vformat("2-bpp BMP images must have a width that is a multiple of 4, but the imported BMP is %d pixels wide.", int(width))); + ERR_FAIL_COND_V_MSG(height % 4 != 0, ERR_UNAVAILABLE, + vformat("2-bpp BMP images must have a height that is a multiple of 4, but the imported BMP is %d pixels tall.", int(height))); + } else if (bits_per_pixel == 4) { // Requires bit unpacking... ERR_FAIL_COND_V_MSG(width % 2 != 0, ERR_UNAVAILABLE, @@ -88,7 +95,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, const uint32_t line_width = (width_bytes + 3) & ~3; // The actual data traversal is determined by - // the data width in case of 8/4/1 bit images + // the data width in case of 8/4/2/1 bit images const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes; const uint8_t *line = p_buffer + (line_width * (height - 1)); const uint8_t *end_buffer = p_buffer + p_header.bmp_file_header.bmp_file_size - p_header.bmp_file_header.bmp_file_offset; @@ -114,6 +121,17 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, index += 8; line_ptr += 1; } break; + case 2: { + uint8_t color_index = *line_ptr; + + write_buffer[index + 0] = (color_index >> 6) & 3; + write_buffer[index + 1] = (color_index >> 4) & 3; + write_buffer[index + 2] = (color_index >> 2) & 3; + write_buffer[index + 3] = color_index & 3; + + index += 4; + line_ptr += 1; + } break; case 4: { uint8_t color_index = *line_ptr; diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp index b5192bd664..a6aeec54cc 100644 --- a/modules/etcpak/image_compress_etcpak.cpp +++ b/modules/etcpak/image_compress_etcpak.cpp @@ -33,8 +33,8 @@ #include "core/os/os.h" #include "core/string/print_string.h" -#include "thirdparty/etcpak/ProcessDxtc.hpp" -#include "thirdparty/etcpak/ProcessRGB.hpp" +#include <ProcessDxtc.hpp> +#include <ProcessRGB.hpp> EtcpakType _determine_etc_type(Image::UsedChannels p_channels) { switch (p_channels) { @@ -130,7 +130,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) { target_format = Image::FORMAT_DXT5; } else { - ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format."); + ERR_FAIL_MSG("Invalid or unsupported etcpak compression format, not ETC or DXT."); } // Compress image data and (if required) mipmaps. @@ -171,7 +171,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua const uint8_t *src_read = r_img->get_data().ptr(); - print_verbose(vformat("ETCPAK: Encoding image size %dx%d to format %s.", width, height, Image::get_format_name(target_format))); + print_verbose(vformat("etcpak: Encoding image size %dx%d to format %s%s.", width, height, Image::get_format_name(target_format), mipmaps ? ", with mipmaps" : "")); int dest_size = Image::get_image_data_size(width, height, target_format, mipmaps); Vector<uint8_t> dest_data; @@ -232,12 +232,12 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) { CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w); } else { - ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format."); + ERR_FAIL_MSG("etcpak: Invalid or unsupported compression format."); } } // Replace original image with compressed one. r_img->set_data(width, height, mipmaps, target_format, dest_data); - print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time))); + print_verbose(vformat("etcpak: Encoding took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time))); } diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index fd748ea569..3fe741a582 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -553,6 +553,7 @@ @icon("res://path/to/class/icon.svg") [/codeblock] [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported. + [b]Note:[/b] As annotations describe their subject, the [code]@icon[/code] annotation must be placed before the class definition and inheritance. </description> </annotation> <annotation name="@onready"> @@ -585,6 +586,7 @@ @tool extends Node [/codeblock] + [b]Note:[/b] As annotations describe their subject, the [code]@tool[/code] annotation must be placed before the class definition and inheritance. </description> </annotation> <annotation name="@warning_ignore" qualifiers="vararg"> diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 8246c96c15..1a102bd16f 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -11,12 +11,6 @@ <link title="GDScript documentation index">$DOCS_URL/tutorials/scripting/gdscript/index.html</link> </tutorials> <methods> - <method name="get_as_byte_code" qualifiers="const"> - <return type="PackedByteArray" /> - <description> - Returns byte code for the script source code. - </description> - </method> <method name="new" qualifiers="vararg"> <return type="Variant" /> <description> diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 28f478e9cd..6b325d6451 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -248,6 +248,10 @@ Ref<Script> GDScript::get_base_script() const { } } +StringName GDScript::get_global_name() const { + return name; +} + StringName GDScript::get_instance_base_type() const { if (native.is_valid()) { return native->get_name(); @@ -1007,17 +1011,6 @@ void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { void GDScript::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new")); - - ClassDB::bind_method(D_METHOD("get_as_byte_code"), &GDScript::get_as_byte_code); -} - -Vector<uint8_t> GDScript::get_as_byte_code() const { - return Vector<uint8_t>(); -}; - -// TODO: Fully remove this. There's not this kind of "bytecode" anymore. -Error GDScript::load_byte_code(const String &p_path) { - return ERR_COMPILATION_FAILED; } void GDScript::set_path(const String &p_path, bool p_take_over) { @@ -2647,8 +2640,6 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str Error err; Ref<GDScript> scr = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE); - // TODO: Reintroduce binary and encrypted scripts. - if (scr.is_null()) { // Don't fail loading because of parsing error. scr.instantiate(); @@ -2663,9 +2654,6 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("gd"); - // TODO: Reintroduce binary and encrypted scripts. - // p_extensions->push_back("gdc"); - // p_extensions->push_back("gde"); } bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const { @@ -2674,8 +2662,7 @@ bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const { String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const { String el = p_path.get_extension().to_lower(); - // TODO: Reintroduce binary and encrypted scripts. - if (el == "gd" /*|| el == "gdc" || el == "gde"*/) { + if (el == "gd") { return "GDScript"; } return ""; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index a53785a98d..82d04f641c 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -228,6 +228,7 @@ public: virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; + virtual StringName get_global_name() const override; virtual StringName get_instance_base_type() const override; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this) override; @@ -250,9 +251,6 @@ public: virtual void set_path(const String &p_path, bool p_take_over = false) override; String get_script_path() const; Error load_source_code(const String &p_path); - Error load_byte_code(const String &p_path); - - Vector<uint8_t> get_as_byte_code() const; bool get_property_default_value(const StringName &p_property, Variant &r_value) const override; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 1b488d560c..e04a962dcb 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1722,21 +1722,52 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { if (list_resolved) { variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; variable_type.kind = GDScriptParser::DataType::BUILTIN; - variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else? - p_for->variable->set_datatype(variable_type); + variable_type.builtin_type = Variant::INT; } else if (p_for->list) { resolve_node(p_for->list, false); - if (p_for->list->datatype.has_container_element_type()) { - variable_type = p_for->list->datatype.get_container_element_type(); - variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; - } else if (p_for->list->datatype.is_typed_container_type()) { - variable_type = p_for->list->datatype.get_typed_container_type(); - variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; - } else { - // Last resort - // TODO: Must other cases be handled? Must we mark as unsafe? - variable_type.type_source = GDScriptParser::DataType::UNDETECTED; + GDScriptParser::DataType list_type = p_for->list->get_datatype(); + if (!list_type.is_hard_type()) { + mark_node_unsafe(p_for->list); + } + if (list_type.is_variant()) { + variable_type.kind = GDScriptParser::DataType::VARIANT; + mark_node_unsafe(p_for->list); + } else if (list_type.has_container_element_type()) { + variable_type = list_type.get_container_element_type(); + variable_type.type_source = list_type.type_source; + } else if (list_type.is_typed_container_type()) { + variable_type = list_type.get_typed_container_type(); + variable_type.type_source = list_type.type_source; + } else if (list_type.builtin_type == Variant::INT || list_type.builtin_type == Variant::FLOAT || list_type.builtin_type == Variant::STRING) { + variable_type.type_source = list_type.type_source; + variable_type.kind = GDScriptParser::DataType::BUILTIN; + variable_type.builtin_type = list_type.builtin_type; + } else if (list_type.builtin_type == Variant::VECTOR2I || list_type.builtin_type == Variant::VECTOR3I) { + variable_type.type_source = list_type.type_source; + variable_type.kind = GDScriptParser::DataType::BUILTIN; + variable_type.builtin_type = Variant::INT; + } else if (list_type.builtin_type == Variant::VECTOR2 || list_type.builtin_type == Variant::VECTOR3) { + variable_type.type_source = list_type.type_source; + variable_type.kind = GDScriptParser::DataType::BUILTIN; + variable_type.builtin_type = Variant::FLOAT; + } else if (list_type.builtin_type == Variant::OBJECT) { + GDScriptParser::DataType return_type; + List<GDScriptParser::DataType> par_types; + int default_arg_count = 0; + bool is_static = false; + bool is_vararg = false; + if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, is_static, is_vararg)) { + variable_type = return_type; + variable_type.type_source = list_type.type_source; + } else if (!list_type.is_hard_type()) { + variable_type.kind = GDScriptParser::DataType::VARIANT; + } else { + push_error(vformat(R"(Unable to iterate on object of type "%s".)", list_type.to_string()), p_for->list); + } + } else if (list_type.builtin_type == Variant::ARRAY || list_type.builtin_type == Variant::DICTIONARY || !list_type.is_hard_type()) { variable_type.kind = GDScriptParser::DataType::VARIANT; + } else { + push_error(vformat(R"(Unable to iterate on value of type "%s".)", list_type.to_string()), p_for->list); } } if (p_for->variable) { @@ -2910,8 +2941,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base_set_class(GDScriptParser::Ide p_identifier->set_datatype(p_identifier_datatype); Error err = OK; - GDScript *scr = GDScriptCache::get_full_script(p_identifier_datatype.script_path, err).ptr(); - ERR_FAIL_COND_MSG(err != OK, "Error while getting full script."); + GDScript *scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err).ptr(); + ERR_FAIL_COND_MSG(err != OK, vformat(R"(Error while getting cache for script "%s".)", p_identifier_datatype.script_path)); scr = scr->find_class(p_identifier_datatype.class_type->fqcn); p_identifier->reduced_value = scr; p_identifier->is_constant = true; @@ -3140,7 +3171,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident for (int i = 0; i < current_enum->values.size(); i++) { const GDScriptParser::EnumNode::Value &element = current_enum->values[i]; if (element.identifier->name == p_identifier->name) { - StringName enum_name = current_enum->identifier->name ? current_enum->identifier->name : UNNAMED_ENUM; + StringName enum_name = current_enum->identifier ? current_enum->identifier->name : UNNAMED_ENUM; GDScriptParser::DataType type = make_enum_type(enum_name, parser->current_class->fqcn, false); if (element.parent_enum->identifier) { type.enum_type = element.parent_enum->identifier->name; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 77c6690d20..d63a1b4536 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -213,7 +213,7 @@ static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScr } GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) { - if (p_expression->is_constant && !p_expression->get_datatype().is_meta_type) { + if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) { return codegen.add_constant(p_expression->reduced_value); } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 97d5c1d8b2..4228046ba2 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -41,6 +41,7 @@ #include "core/os/os.h" #include "core/string/string_builder.h" #include "gdscript_warning.h" +#include "servers/text_server.h" #endif // DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -186,24 +187,6 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) { } #ifdef DEBUG_ENABLED -void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) { - ERR_FAIL_COND(p_source == nullptr); - Vector<String> symbols; - if (!p_symbol1.is_empty()) { - symbols.push_back(p_symbol1); - } - if (!p_symbol2.is_empty()) { - symbols.push_back(p_symbol2); - } - if (!p_symbol3.is_empty()) { - symbols.push_back(p_symbol3); - } - if (!p_symbol4.is_empty()) { - symbols.push_back(p_symbol4); - } - push_warning(p_source, p_code, symbols); -} - void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols) { ERR_FAIL_COND(p_source == nullptr); if (is_ignoring_warnings) { @@ -540,43 +523,28 @@ void GDScriptParser::parse_program() { head = alloc_node<ClassNode>(); head->fqcn = script_path; current_class = head; + bool can_have_class_or_extends = true; - // If we happen to parse an annotation before extends or class_name keywords, track it. - // @tool is allowed, but others should fail. - AnnotationNode *premature_annotation = nullptr; - - if (match(GDScriptTokenizer::Token::ANNOTATION)) { - // Check for @tool, script-level, or standalone annotation. + while (match(GDScriptTokenizer::Token::ANNOTATION)) { AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL); if (annotation != nullptr) { - if (annotation->name == SNAME("@tool")) { - // TODO: don't allow @tool anywhere else. (Should all script annotations be the first thing?). - _is_tool = true; - if (previous.type != GDScriptTokenizer::Token::NEWLINE) { - push_error(R"(Expected newline after "@tool" annotation.)"); - } - // @tool annotation has no specific target. - annotation->apply(this, nullptr); - } else if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) { - premature_annotation = annotation; - if (previous.type != GDScriptTokenizer::Token::NEWLINE) { - push_error(R"(Expected newline after a standalone annotation.)"); - } + if (annotation->applies_to(AnnotationInfo::SCRIPT)) { annotation->apply(this, head); } else { - premature_annotation = annotation; annotation_stack.push_back(annotation); + // This annotation must appear after script-level annotations + // and class_name/extends (ex: could be @onready or @export), + // so we stop looking for script-level stuff. + can_have_class_or_extends = false; + break; } } } - for (bool should_break = false; !should_break;) { + while (can_have_class_or_extends) { // Order here doesn't matter, but there should be only one of each at most. switch (current.type) { case GDScriptTokenizer::Token::CLASS_NAME: - if (premature_annotation != nullptr) { - push_error(R"("class_name" should be used before annotations (except @tool).)"); - } advance(); if (head->identifier != nullptr) { push_error(R"("class_name" can only be used once.)"); @@ -585,9 +553,6 @@ void GDScriptParser::parse_program() { } break; case GDScriptTokenizer::Token::EXTENDS: - if (premature_annotation != nullptr) { - push_error(R"("extends" should be used before annotations (except @tool).)"); - } advance(); if (head->extends_used) { push_error(R"("extends" can only be used once.)"); @@ -597,7 +562,8 @@ void GDScriptParser::parse_program() { } break; default: - should_break = true; + // No tokens are allowed between script annotations and class/extends. + can_have_class_or_extends = false; break; } @@ -606,21 +572,6 @@ void GDScriptParser::parse_program() { } } - if (match(GDScriptTokenizer::Token::ANNOTATION)) { - // Check for a script-level, or standalone annotation. - AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL); - if (annotation != nullptr) { - if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) { - if (previous.type != GDScriptTokenizer::Token::NEWLINE) { - push_error(R"(Expected newline after a standalone annotation.)"); - } - annotation->apply(this, head); - } else { - annotation_stack.push_back(annotation); - } - } - } - parse_class_body(true); complete_extents(head); @@ -2283,7 +2234,14 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_expression(bool p_can_assi } GDScriptParser::IdentifierNode *GDScriptParser::parse_identifier() { - return static_cast<IdentifierNode *>(parse_identifier(nullptr, false)); + IdentifierNode *identifier = static_cast<IdentifierNode *>(parse_identifier(nullptr, false)); +#ifdef DEBUG_ENABLED + // Check for spoofing here (if available in TextServer) since this isn't called inside expressions. This is only relevant for declarations. + if (identifier && TS->has_feature(TextServer::FEATURE_UNICODE_SECURITY) && TS->spoof_check(identifier->name.operator String())) { + push_warning(identifier, GDScriptWarning::CONFUSABLE_IDENTIFIER, identifier->name.operator String()); + } +#endif + return identifier; } GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode *p_previous_operand, bool p_can_assign) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 0903f62061..f6d2a8feee 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1361,8 +1361,11 @@ private: void clear(); void push_error(const String &p_message, const Node *p_origin = nullptr); #ifdef DEBUG_ENABLED - void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const String &p_symbol1 = String(), const String &p_symbol2 = String(), const String &p_symbol3 = String(), const String &p_symbol4 = String()); void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols); + template <typename... Symbols> + void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Symbols &...p_symbols) { + push_warning(p_source, p_code, Vector<String>{ p_symbols... }); + } #endif void make_completion_context(CompletionType p_type, Node *p_node, int p_argument = -1, bool p_force = false); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index e17a804003..d7f1114fd3 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -31,10 +31,14 @@ #include "gdscript_tokenizer.h" #include "core/error/error_macros.h" +#include "core/string/char_utils.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" #endif +#ifdef DEBUG_ENABLED +#include "servers/text_server.h" +#endif static const char *token_names[] = { "Empty", // EMPTY, @@ -435,10 +439,12 @@ GDScriptTokenizer::Token GDScriptTokenizer::check_vcs_marker(char32_t p_test, To } GDScriptTokenizer::Token GDScriptTokenizer::annotation() { - if (!is_ascii_identifier_char(_peek())) { + if (is_unicode_identifier_start(_peek())) { + _advance(); // Consume start character. + } else { push_error("Expected annotation identifier after \"@\"."); } - while (is_ascii_identifier_char(_peek())) { + while (is_unicode_identifier_continue(_peek())) { // Consume all identifier characters. _advance(); } @@ -447,7 +453,6 @@ GDScriptTokenizer::Token GDScriptTokenizer::annotation() { return annotation; } -GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() { #define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ KEYWORD_GROUP('a') \ KEYWORD("as", Token::AS) \ @@ -512,8 +517,21 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() { #define MIN_KEYWORD_LENGTH 2 #define MAX_KEYWORD_LENGTH 10 - // Consume all alphanumeric characters. - while (is_ascii_identifier_char(_peek())) { +#ifdef DEBUG_ENABLED +void GDScriptTokenizer::make_keyword_list() { +#define KEYWORD_LINE(keyword, token_type) keyword, +#define KEYWORD_GROUP_IGNORE(group) + keyword_list = { + KEYWORDS(KEYWORD_GROUP_IGNORE, KEYWORD_LINE) + }; +#undef KEYWORD_LINE +#undef KEYWORD_GROUP_IGNORE +} +#endif // DEBUG_ENABLED + +GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() { + // Consume all identifier characters. + while (is_unicode_identifier_continue(_peek())) { _advance(); } @@ -565,15 +583,28 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() { } // Not a keyword, so must be an identifier. - return make_identifier(name); + Token id = make_identifier(name); + +#ifdef DEBUG_ENABLED + // Additional checks for identifiers but only in debug and if it's available in TextServer. + if (TS->has_feature(TextServer::FEATURE_UNICODE_SECURITY)) { + int64_t confusable = TS->is_confusable(name, keyword_list); + if (confusable >= 0) { + push_error(vformat(R"(Identifier "%s" is visually similar to the GDScript keyword "%s" and thus not allowed.)", name, keyword_list[confusable])); + } + } +#endif // DEBUG_ENABLED + + return id; -#undef KEYWORDS -#undef MIN_KEYWORD_LENGTH -#undef MAX_KEYWORD_LENGTH #undef KEYWORD_GROUP_CASE #undef KEYWORD } +#undef MAX_KEYWORD_LENGTH +#undef MIN_KEYWORD_LENGTH +#undef KEYWORDS + void GDScriptTokenizer::newline(bool p_make_token) { // Don't overwrite previous newline, nor create if we want a line continuation. if (p_make_token && !pending_newline && !line_continuation) { @@ -720,7 +751,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { error.rightmost_column = column + 1; push_error(error); has_error = true; - } else if (is_ascii_identifier_char(_peek())) { + } else if (is_unicode_identifier_start(_peek()) || is_unicode_identifier_continue(_peek())) { // Letter at the end of the number. push_error("Invalid numeric notation."); } @@ -1311,7 +1342,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { if (is_digit(c)) { return number(); - } else if (is_ascii_identifier_char(c)) { + } else if (is_unicode_identifier_start(c)) { return potential_identifier(); } @@ -1504,7 +1535,11 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { } default: - return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1))); + if (is_whitespace(c)) { + return make_error(vformat(R"(Invalid white space character "\\u%X".)", static_cast<int32_t>(c))); + } else { + return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1))); + } } } @@ -1514,4 +1549,7 @@ GDScriptTokenizer::GDScriptTokenizer() { tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size"); } #endif // TOOLS_ENABLED +#ifdef DEBUG_ENABLED + make_keyword_list(); +#endif // DEBUG_ENABLED } diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index 9588922122..608840d3f1 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -224,6 +224,9 @@ private: char32_t indent_char = '\0'; int position = 0; int length = 0; +#ifdef DEBUG_ENABLED + Vector<String> keyword_list; +#endif // DEBUG_ENABLED #ifdef TOOLS_ENABLED HashMap<int, CommentData> comments; @@ -239,6 +242,10 @@ private: void _skip_whitespace(); void check_indent(); +#ifdef DEBUG_ENABLED + void make_keyword_list(); +#endif // DEBUG_ENABLED + Token make_error(const String &p_message); void push_error(const String &p_message); void push_error(const Token &p_error); diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 184cecb316..a6cbb7f6ae 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -155,6 +155,10 @@ String GDScriptWarning::get_message() const { CHECK_SYMBOLS(2); return vformat(R"(The function '%s()' is a static function but was called from an instance. Instead, it should be directly called from the type: '%s.%s()'.)", symbols[0], symbols[1], symbols[0]); } + case CONFUSABLE_IDENTIFIER: { + CHECK_SYMBOLS(1); + return vformat(R"(The identifier "%s" has misleading characters and might be confused with something else.)", symbols[0]); + } case WARNING_MAX: break; // Can't happen, but silences warning } @@ -219,6 +223,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "SHADOWED_GLOBAL_IDENTIFIER", "INT_ASSIGNED_TO_ENUM", "STATIC_CALLED_ON_INSTANCE", + "CONFUSABLE_IDENTIFIER", }; static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names."); diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index e3aee45f33..b485f02b9c 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -78,6 +78,7 @@ public: SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable. INT_ASSIGNED_TO_ENUM, // An integer value was assigned to an enum-typed variable without casting. STATIC_CALLED_ON_INSTANCE, // A static method was called on an instance of a class instead of on the class itself. + CONFUSABLE_IDENTIFIER, // The identifier contains misleading characters that can be confused. E.g. "usеr" (has Cyrillic "е" instead of Latin "e"). WARNING_MAX, }; diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index edb2e8117a..b9e6921034 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -107,6 +107,7 @@ void GDScriptTextDocument::didSave(const Variant &p_param) { } else { scr->reload(true); } + scr->update_exports(); ScriptEditor::get_singleton()->update_docs_from_script(scr); } } diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 33b5ae6942..b6feaadccf 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -71,21 +71,18 @@ class EditorExportGDScript : public EditorExportPlugin { public: virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override { - int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED; String script_key; const Ref<EditorExportPreset> &preset = get_export_preset(); if (preset.is_valid()) { - script_mode = preset->get_script_export_mode(); script_key = preset->get_script_encryption_key().to_lower(); } - if (!p_path.ends_with(".gd") || script_mode == EditorExportPreset::MODE_SCRIPT_TEXT) { + if (!p_path.ends_with(".gd")) { return; } - // TODO: Re-add compiled GDScript on export. return; } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd new file mode 100644 index 0000000000..cf56a0a933 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd @@ -0,0 +1,6 @@ +const constant_float = 1.0 + +func test(): + for x in constant_float: + if x is String: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out new file mode 100644 index 0000000000..e309831b3e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "float" so it can't be of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd new file mode 100644 index 0000000000..5ee8ac19e1 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd @@ -0,0 +1,6 @@ +const constant_int = 1 + +func test(): + for x in constant_int: + if x is String: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out new file mode 100644 index 0000000000..54c190cf8a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "int" so it can't be of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd new file mode 100644 index 0000000000..b3db4f3b49 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd @@ -0,0 +1,6 @@ +enum { enum_value = 1 } + +func test(): + for x in enum_value: + if x is String: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out new file mode 100644 index 0000000000..54c190cf8a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "int" so it can't be of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd new file mode 100644 index 0000000000..87c54f7402 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd @@ -0,0 +1,6 @@ +func test(): + var hard_float := 1.0 + + for x in hard_float: + if x is String: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out new file mode 100644 index 0000000000..e309831b3e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "float" so it can't be of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd new file mode 100644 index 0000000000..2a43f5a930 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd @@ -0,0 +1,6 @@ +func test(): + var hard_int := 1 + + for x in hard_int: + if x is String: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out new file mode 100644 index 0000000000..54c190cf8a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "int" so it can't be of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd new file mode 100644 index 0000000000..c3920d35b3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd @@ -0,0 +1,14 @@ +class Iterator: + func _iter_init(_count): + return true + func _iter_next(_count): + return false + func _iter_get(_count) -> StringName: + return &'custom' + +func test(): + var hard_iterator := Iterator.new() + + for x in hard_iterator: + if x is int: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out new file mode 100644 index 0000000000..a48591a3b4 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "StringName" so it can't be of type "int". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd new file mode 100644 index 0000000000..b36d87aabe --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd @@ -0,0 +1,6 @@ +func test(): + var hard_string := 'a' + + for x in hard_string: + if x is int: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out new file mode 100644 index 0000000000..92c5ebc599 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "String" so it can't be of type "int". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd new file mode 100644 index 0000000000..060a8bedf9 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd @@ -0,0 +1,3 @@ +func test(): + for x in true: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out new file mode 100644 index 0000000000..94cb038885 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Unable to iterate on value of type "bool". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd new file mode 100644 index 0000000000..6cfc822482 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd @@ -0,0 +1,4 @@ +func test(): + for x in 1: + if x is String: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out new file mode 100644 index 0000000000..54c190cf8a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Expression is of type "int" so it can't be of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd new file mode 100644 index 0000000000..f351fc1f7b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd @@ -0,0 +1,7 @@ +enum { + V1, + V2 = V1, +} + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd new file mode 100644 index 0000000000..7b74be6f2c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd @@ -0,0 +1,15 @@ +func test(): + var variant_int: Variant = 1 + var weak_int = 1 + + for x in variant_int: + if x is String: + print('never') + print(x) + + for x in weak_int: + if x is String: + print('never') + print(x) + + print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out new file mode 100644 index 0000000000..7677671cfd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out @@ -0,0 +1,4 @@ +GDTEST_OK +0 +0 +ok diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out index b018091c18..32e230fc80 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out @@ -2,4 +2,4 @@ GDTEST_OK >> WARNING >> Line: 2 >> UNUSED_PARAMETER ->> +>> The parameter 'unused' is never used in the function ''. If this is intended, prefix it with an underscore: '_unused' diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd index 179e454073..0085b3f367 100644 --- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd @@ -1,6 +1,6 @@ -# Error here. `class_name` should be used *before* annotations, not after (except @tool). -@icon("res://path/to/optional/icon.svg") +# Error here. Annotations should be used before `class_name`, not after. class_name HelloWorld +@icon("res://path/to/optional/icon.svg") func test(): pass diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out index 02b33c8692..a598ff8424 100644 --- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -"class_name" should be used before annotations (except @tool). +Annotation "@icon" is not allowed in this level. diff --git a/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd new file mode 100644 index 0000000000..4b1f284070 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd @@ -0,0 +1,3 @@ +func test(): + var аs # Using Cyrillic "а". + print(аs) diff --git a/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out new file mode 100644 index 0000000000..337dec2f4d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Identifier "аs" is visually similar to the GDScript keyword "as" and thus not allowed. diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.gd b/modules/gdscript/tests/scripts/parser/features/class_name.gd index 8bd188e247..19009e433d 100644 --- a/modules/gdscript/tests/scripts/parser/features/class_name.gd +++ b/modules/gdscript/tests/scripts/parser/features/class_name.gd @@ -1,5 +1,5 @@ -class_name HelloWorld @icon("res://path/to/optional/icon.svg") +class_name HelloWorld func test(): pass diff --git a/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd new file mode 100644 index 0000000000..523959a016 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd @@ -0,0 +1,35 @@ +const Ï€ = PI +var ã„¥ = Ï€ + +func test(): + var ÖƒÕ¸Ö€Õ±Õ¡Ö€Õ¯Õ¸Ö‚Õ´ = "test" + prints("ÖƒÕ¸Ö€Õ±Õ¡Ö€Õ¯Õ¸Ö‚Õ´", ÖƒÕ¸Ö€Õ±Õ¡Ö€Õ¯Õ¸Ö‚Õ´) + var امتØان = "test" + prints("امتØان", امتØان) + var পরীকà§à¦·à¦¾ = "test" + prints("পরীকà§à¦·à¦¾", পরীকà§à¦·à¦¾) + var теÑÑ‚ = "test" + prints("теÑÑ‚", теÑÑ‚) + var जाà¤à¤š = "test" + prints("जाà¤à¤š", जाà¤à¤š) + var 기준 = "test" + prints("기준", 기준) + var 测试 = "test" + prints("测试", 测试) + var テスト = "test" + prints("テスト", テスト) + var 試験 = "test" + prints("試験", 試験) + var പരീകàµà´· = "test" + prints("പരീകàµà´·", പരീകàµà´·) + var ทดสà¸à¸š = "test" + prints("ทดสà¸à¸š", ทดสà¸à¸š) + var δοκιμή = "test" + prints("δοκιμή", δοκιμή) + + const d = 1.1 + _process(d) + print(is_equal_approx(ã„¥, PI + (d * PI))) + +func _process(Δ: float) -> void: + ã„¥ += Δ * Ï€ diff --git a/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out new file mode 100644 index 0000000000..c071380a8f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out @@ -0,0 +1,14 @@ +GDTEST_OK +ÖƒÕ¸Ö€Õ±Õ¡Ö€Õ¯Õ¸Ö‚Õ´ test +امتØان test +পরীকà§à¦·à¦¾ test +теÑÑ‚ test +जाà¤à¤š test +기준 test +测试 test +テスト test +試験 test +പരീകàµà´· test +ทดสà¸à¸š test +δοκιμή test +true diff --git a/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd new file mode 100644 index 0000000000..e2caac8ffd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd @@ -0,0 +1,5 @@ +func test(): + var port = 0 # Only latin characters. + var pοrt = 1 # The "ο" is Greek omicron. + + prints(port, pοrt) diff --git a/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out new file mode 100644 index 0000000000..c483396443 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out @@ -0,0 +1,6 @@ +GDTEST_OK +>> WARNING +>> Line: 3 +>> CONFUSABLE_IDENTIFIER +>> The identifier "pοrt" has misleading characters and might be confused with something else. +0 1 diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd new file mode 100644 index 0000000000..81355e0255 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd @@ -0,0 +1,51 @@ +const constant_float = 1.0 +const constant_int = 1 +enum { enum_value = 1 } + +class Iterator: + func _iter_init(_count): + return true + func _iter_next(_count): + return false + func _iter_get(_count) -> StringName: + return &'custom' + +func test(): + var hard_float := 1.0 + var hard_int := 1 + var hard_string := '0' + var hard_iterator := Iterator.new() + + var variant_float: Variant = hard_float + var variant_int: Variant = hard_int + var variant_string: Variant = hard_string + var variant_iterator: Variant = hard_iterator + + for i in 1.0: + print(typeof(i) == TYPE_FLOAT) + for i in 1: + print(typeof(i) == TYPE_INT) + for i in 'a': + print(typeof(i) == TYPE_STRING) + for i in Iterator.new(): + print(typeof(i) == TYPE_STRING_NAME) + + for i in hard_float: + print(typeof(i) == TYPE_FLOAT) + for i in hard_int: + print(typeof(i) == TYPE_INT) + for i in hard_string: + print(typeof(i) == TYPE_STRING) + for i in hard_iterator: + print(typeof(i) == TYPE_STRING_NAME) + + for i in variant_float: + print(typeof(i) == TYPE_FLOAT) + for i in variant_int: + print(typeof(i) == TYPE_INT) + for i in variant_string: + print(typeof(i) == TYPE_STRING) + for i in variant_iterator: + print(typeof(i) == TYPE_STRING_NAME) + + print('ok') diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out new file mode 100644 index 0000000000..b3e82d52ef --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out @@ -0,0 +1,14 @@ +GDTEST_OK +true +true +true +true +true +true +true +true +true +true +true +true +ok diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 788a70f640..b243ba933d 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3124,10 +3124,11 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p // API for that in Godot, so we'd have to load as a buffer (i.e. embedded in // the material), so we do this only as fallback. Ref<Texture2D> texture = ResourceLoader::load(uri); + String extension = uri.get_extension().to_lower(); if (texture.is_valid()) { p_state->images.push_back(texture); continue; - } else if (mimetype == "image/png" || mimetype == "image/jpeg") { + } else if (mimetype == "image/png" || mimetype == "image/jpeg" || extension == "png" || extension == "jpg" || extension == "jpeg") { // Fallback to loading as byte array. // This enables us to support the spec's requirement that we honor mimetype // regardless of file URI. @@ -6071,6 +6072,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ const int track_idx = animation->get_track_count(); animation->add_track(Animation::TYPE_BLEND_SHAPE); animation->track_set_path(track_idx, blend_path); + animation->track_set_imported(track_idx, true); //helps merging later // Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation, // the other modes have to be baked. diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index e39127e0a1..ca94917938 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -113,6 +113,11 @@ void CSharpLanguage::init() { BindingsGenerator::handle_cmdline_args(cmdline_args); #endif + GLOBAL_DEF("dotnet/project/assembly_name", ""); +#ifdef TOOLS_ENABLED + GLOBAL_DEF("dotnet/project/solution_directory", ""); +#endif + gdmono = memnew(GDMono); gdmono->initialize(); @@ -2601,6 +2606,10 @@ Ref<Script> CSharpScript::get_base_script() const { return base_script; } +StringName CSharpScript::get_global_name() const { + return StringName(); +} + void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const { #ifdef TOOLS_ENABLED const CSharpScript *top = this; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index ef381fd76a..6021555255 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -186,6 +186,8 @@ public: bool inherits_script(const Ref<Script> &p_script) const override; Ref<Script> get_base_script() const override; + StringName get_global_name() const override; + ScriptLanguage *get_language() const override; void get_script_method_list(List<MethodInfo> *p_list) const override; diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 745a8b73f8..db96003baf 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -17,6 +17,8 @@ namespace GodotTools.Export { public partial class ExportPlugin : EditorExportPlugin { + public override string _GetName() => "C#"; + private List<string> _tempFolders = new List<string>(); public void RegisterExportSettings() diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index de10c04e31..08147d9f6a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -411,8 +411,6 @@ namespace GodotTools _editorSettings = editorInterface.GetEditorSettings(); - GodotSharpDirs.RegisterProjectSettings(); - _errorDialog = new AcceptDialog(); editorBaseControl.AddChild(_errorDialog); diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs index 4e892be55c..7624989092 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs @@ -48,12 +48,6 @@ namespace GodotTools.Internals } } - public static void RegisterProjectSettings() - { - GlobalDef("dotnet/project/assembly_name", ""); - GlobalDef("dotnet/project/solution_directory", ""); - } - public static void DetermineProjectLocation() { static string DetermineProjectName() diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index c0d88553ad..03cbfda1bd 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1864,12 +1864,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append("\n" OPEN_BLOCK_L1); if (getter) { - p_output.append(INDENT2 "get\n" - - // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) - "#pragma warning disable CS0618 // Disable warning about obsolete method\n" - - OPEN_BLOCK_L2 INDENT3); + p_output.append(INDENT2 "get\n" OPEN_BLOCK_L2 INDENT3); p_output.append("return "); p_output.append(getter->proxy_name + "("); @@ -1884,21 +1879,11 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(itos(p_iprop.index)); } } - p_output.append(");\n" - - CLOSE_BLOCK_L2 - - // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) - "#pragma warning restore CS0618\n"); + p_output.append(");\n" CLOSE_BLOCK_L2); } if (setter) { - p_output.append(INDENT2 "set\n" - - // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) - "#pragma warning disable CS0618 // Disable warning about obsolete method\n" - - OPEN_BLOCK_L2 INDENT3); + p_output.append(INDENT2 "set\n" OPEN_BLOCK_L2 INDENT3); p_output.append(setter->proxy_name + "("); if (p_iprop.index != -1) { @@ -1912,12 +1897,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(itos(p_iprop.index) + ", "); } } - p_output.append("value);\n" - - CLOSE_BLOCK_L2 - - // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that) - "#pragma warning restore CS0618\n"); + p_output.append("value);\n" CLOSE_BLOCK_L2); } p_output.append(CLOSE_BLOCK_L1); @@ -3056,12 +3036,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() { HashMap<StringName, StringName>::Iterator accessor = accessor_methods.find(imethod.cname); if (accessor) { - const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value); - - // We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also - // we don't know if an accessor method in a different class could have other purposes, so better leave those untouched. - imethod.is_deprecated = true; - imethod.deprecation_message = imethod.proxy_name + " is deprecated. Use the " + accessor_property->proxy_name + " property instead."; + // We only make internal an accessor method if it's in the same class as the property. + // It's easier this way, but also we don't know if an accessor method in a different class + // could have other purposes, so better leave those untouched. + imethod.is_internal = true; } if (itype.class_doc) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 19f7c54847..b57317e1d0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -816,26 +816,26 @@ namespace Godot public Basis(Vector3 axis, real_t angle) { Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); - real_t cosine = Mathf.Cos(angle); - Row0.x = axisSq.x + cosine * (1.0f - axisSq.x); - Row1.y = axisSq.y + cosine * (1.0f - axisSq.y); - Row2.z = axisSq.z + cosine * (1.0f - axisSq.z); + (real_t sin, real_t cos) = Mathf.SinCos(angle); - real_t sine = Mathf.Sin(angle); - real_t t = 1.0f - cosine; + Row0.x = axisSq.x + cos * (1.0f - axisSq.x); + Row1.y = axisSq.y + cos * (1.0f - axisSq.y); + Row2.z = axisSq.z + cos * (1.0f - axisSq.z); + + real_t t = 1.0f - cos; real_t xyzt = axis.x * axis.y * t; - real_t zyxs = axis.z * sine; + real_t zyxs = axis.z * sin; Row0.y = xyzt - zyxs; Row1.x = xyzt + zyxs; xyzt = axis.x * axis.z * t; - zyxs = axis.y * sine; + zyxs = axis.y * sin; Row0.z = xyzt + zyxs; Row2.x = xyzt - zyxs; xyzt = axis.y * axis.z * t; - zyxs = axis.x * sine; + zyxs = axis.x * sin; Row1.z = xyzt - zyxs; Row2.y = xyzt + zyxs; } @@ -885,19 +885,29 @@ namespace Godot /// <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)); + (real_t sin, real_t cos) = Mathf.SinCos(euler.x); + Basis xmat = new Basis + ( + new Vector3(1, 0, 0), + new Vector3(0, cos, sin), + new Vector3(0, -sin, cos) + ); - 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)); + (sin, cos) = Mathf.SinCos(euler.y); + Basis ymat = new Basis + ( + new Vector3(cos, 0, -sin), + new Vector3(0, 1, 0), + new Vector3(sin, 0, cos) + ); - 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)); + (sin, cos) = Mathf.SinCos(euler.z); + Basis zmat = new Basis + ( + new Vector3(cos, sin, 0), + new Vector3(-sin, cos, 0), + new Vector3(0, 0, 1) + ); switch (order) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 4075a878d2..6a7863112a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -359,24 +359,6 @@ namespace Godot } /// <summary> - /// Returns the result of the linear interpolation between - /// this color and <paramref name="to"/> by color amount <paramref name="weight"/>. - /// </summary> - /// <param name="to">The destination color for interpolation.</param> - /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> - /// <returns>The resulting color of the interpolation.</returns> - public readonly Color Lerp(Color to, Color weight) - { - return new Color - ( - (float)Mathf.Lerp(r, to.r, weight.r), - (float)Mathf.Lerp(g, to.g, weight.g), - (float)Mathf.Lerp(b, to.b, weight.b), - (float)Mathf.Lerp(a, to.a, weight.a) - ); - } - - /// <summary> /// Returns the color converted to the sRGB color space. /// This method assumes the original color is in the linear color space. /// See also <see cref="SrgbToLinear"/> which performs the opposite operation. @@ -815,7 +797,7 @@ namespace Godot { if (saturation == 0) { - // Achromatic (grey) + // Achromatic (gray) return new Color(value, value, value, alpha); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs index ea05c1547c..72a1868964 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs @@ -83,6 +83,17 @@ namespace Godot } /// <summary> + /// Returns the sine and cosine of angle <paramref name="s"/> in radians. + /// </summary> + /// <param name="s">The angle in radians.</param> + /// <returns>The sine and cosine of that angle.</returns> + public static (real_t Sin, real_t Cos) SinCos(real_t s) + { + (double sin, double cos) = Math.SinCos(s); + return ((real_t)sin, (real_t)cos); + } + + /// <summary> /// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately /// equal to each other. /// The comparison is done using the provided tolerance value. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index fd37f8d9e8..f11b3c553a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -381,14 +381,14 @@ namespace Godot } real_t radians = Mathf.DegToRad(fovyDegrees / (real_t)2.0); real_t deltaZ = zFar - zNear; - real_t sine = Mathf.Sin(radians); + (real_t sin, real_t cos) = Mathf.SinCos(radians); - if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) + if ((deltaZ == 0) || (sin == 0) || (aspect == 0)) { return Zero; } - real_t cotangent = Mathf.Cos(radians) / sine; + real_t cotangent = cos / sin; Projection proj = Projection.Identity; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 47106bb402..8e4f9178f7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -542,14 +542,13 @@ namespace Godot } else { - real_t sinAngle = Mathf.Sin(angle * 0.5f); - real_t cosAngle = Mathf.Cos(angle * 0.5f); - real_t s = sinAngle / d; + (real_t sin, real_t cos) = Mathf.SinCos(angle * 0.5f); + real_t s = sin / d; x = axis.x * s; y = axis.y * s; z = axis.z * s; - w = cosAngle; + w = cos; } } @@ -593,12 +592,9 @@ namespace Godot // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) // a3 is the angle of the first rotation, following the notation in this reference. - real_t cosA1 = Mathf.Cos(halfA1); - real_t sinA1 = Mathf.Sin(halfA1); - real_t cosA2 = Mathf.Cos(halfA2); - real_t sinA2 = Mathf.Sin(halfA2); - real_t cosA3 = Mathf.Cos(halfA3); - real_t sinA3 = Mathf.Sin(halfA3); + (real_t sinA1, real_t cosA1) = Mathf.SinCos(halfA1); + (real_t sinA2, real_t cosA2) = Mathf.SinCos(halfA2); + (real_t sinA3, real_t cosA3) = Mathf.SinCos(halfA3); return new Quaternion( (sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3), diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 6dda150c2b..fa060e3a53 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -195,8 +195,10 @@ namespace Godot Vector2 s2 = transform.GetScale(); // Slerp rotation - var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1)); - var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2)); + (real_t sin1, real_t cos1) = Mathf.SinCos(r1); + (real_t sin2, real_t cos2) = Mathf.SinCos(r2); + var v1 = new Vector2(cos1, sin1); + var v2 = new Vector2(cos2, sin2); real_t dot = v1.Dot(v2); @@ -213,7 +215,8 @@ namespace Godot { real_t angle = weight * Mathf.Acos(dot); Vector2 v3 = (v2 - (v1 * dot)).Normalized(); - v = (v1 * Mathf.Cos(angle)) + (v3 * Mathf.Sin(angle)); + (real_t sine, real_t cos) = Mathf.SinCos(angle); + v = (v1 * sine) + (v3 * cos); } // Extract parameters @@ -434,8 +437,9 @@ namespace Godot /// <param name="origin">The origin vector, or column index 2.</param> public Transform2D(real_t rotation, Vector2 origin) { - x.x = y.y = Mathf.Cos(rotation); - x.y = y.x = Mathf.Sin(rotation); + (real_t sin, real_t cos) = Mathf.SinCos(rotation); + x.x = y.y = cos; + x.y = y.x = sin; y.x *= -1; this.origin = origin; } @@ -451,10 +455,12 @@ namespace Godot /// <param name="origin">The origin vector, or column index 2.</param> public Transform2D(real_t rotation, Vector2 scale, real_t skew, Vector2 origin) { - x.x = Mathf.Cos(rotation) * scale.x; - y.y = Mathf.Cos(rotation + skew) * scale.y; - y.x = -Mathf.Sin(rotation + skew) * scale.y; - x.y = Mathf.Sin(rotation) * scale.x; + (real_t rotationSin, real_t rotationCos) = Mathf.SinCos(rotation); + (real_t rotationSkewSin, real_t rotationSkewCos) = Mathf.SinCos(rotation + skew); + x.x = rotationCos * scale.x; + y.y = rotationSkewCos * scale.y; + y.x = -rotationSkewSin * scale.y; + x.y = rotationSin * scale.x; this.origin = origin; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 57cbef1c5c..07cb34cadd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -390,24 +390,6 @@ namespace Godot } /// <summary> - /// Returns the result of the linear interpolation between - /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>. - /// </summary> - /// <param name="to">The destination vector for interpolation.</param> - /// <param name="weight"> - /// A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation. - /// </param> - /// <returns>The resulting vector of the interpolation.</returns> - public readonly Vector2 Lerp(Vector2 to, Vector2 weight) - { - return new Vector2 - ( - Mathf.Lerp(x, to.x, weight.x), - Mathf.Lerp(y, to.y, weight.y) - ); - } - - /// <summary> /// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>. /// </summary> /// <param name="length">The length to limit to.</param> @@ -539,11 +521,12 @@ namespace Godot /// <returns>The rotated vector.</returns> public readonly Vector2 Rotated(real_t angle) { - real_t sine = Mathf.Sin(angle); - real_t cosi = Mathf.Cos(angle); - return new Vector2( - x * cosi - y * sine, - x * sine + y * cosi); + (real_t sin, real_t cos) = Mathf.SinCos(angle); + return new Vector2 + ( + x * cos - y * sin, + x * sin + y * cos + ); } /// <summary> @@ -693,7 +676,8 @@ namespace Godot /// <returns>The resulting vector.</returns> public static Vector2 FromAngle(real_t angle) { - return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); + (real_t sin, real_t cos) = Mathf.SinCos(angle); + return new Vector2(cos, sin); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index 91be548a21..740fedec66 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -95,38 +95,6 @@ namespace Godot } /// <summary> - /// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians. - /// - /// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when - /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>. - /// </summary> - /// <returns>The angle of this vector, in radians.</returns> - public readonly real_t Angle() - { - return Mathf.Atan2(y, x); - } - - /// <summary> - /// Returns the angle to the given vector, in radians. - /// </summary> - /// <param name="to">The other vector to compare this vector to.</param> - /// <returns>The angle between the two vectors, in radians.</returns> - public readonly real_t AngleTo(Vector2i to) - { - return Mathf.Atan2(Cross(to), Dot(to)); - } - - /// <summary> - /// Returns the angle between the line connecting the two points and the X axis, in radians. - /// </summary> - /// <param name="to">The other vector to compare this vector to.</param> - /// <returns>The angle between the two vectors, in radians.</returns> - public readonly real_t AngleToPoint(Vector2i to) - { - return Mathf.Atan2(to.y - y, to.x - x); - } - - /// <summary> /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>. /// </summary> /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns> @@ -153,48 +121,6 @@ namespace Godot } /// <summary> - /// Returns the cross product of this vector and <paramref name="with"/>. - /// </summary> - /// <param name="with">The other vector.</param> - /// <returns>The cross product vector.</returns> - public readonly int Cross(Vector2i with) - { - return x * with.y - y * with.x; - } - - /// <summary> - /// Returns the squared distance between this vector and <paramref name="to"/>. - /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if - /// you need to compare vectors or need the squared distance for some formula. - /// </summary> - /// <param name="to">The other vector to use.</param> - /// <returns>The squared distance between the two vectors.</returns> - public readonly int DistanceSquaredTo(Vector2i to) - { - return (to - this).LengthSquared(); - } - - /// <summary> - /// Returns the distance between this vector and <paramref name="to"/>. - /// </summary> - /// <param name="to">The other vector to use.</param> - /// <returns>The distance between the two vectors.</returns> - public readonly real_t DistanceTo(Vector2i to) - { - return (to - this).Length(); - } - - /// <summary> - /// Returns the dot product of this vector and <paramref name="with"/>. - /// </summary> - /// <param name="with">The other vector to use.</param> - /// <returns>The dot product of the two vectors.</returns> - public readonly int Dot(Vector2i with) - { - return x * with.x + y * with.y; - } - - /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> @@ -242,38 +168,6 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components - /// and <paramref name="mod"/>. - /// </summary> - /// <param name="mod">A value representing the divisor of the operation.</param> - /// <returns> - /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>. - /// </returns> - public readonly Vector2i PosMod(int mod) - { - Vector2i v = this; - v.x = Mathf.PosMod(v.x, mod); - v.y = Mathf.PosMod(v.y, mod); - return v; - } - - /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components - /// and <paramref name="modv"/>'s components. - /// </summary> - /// <param name="modv">A vector representing the divisors of the operation.</param> - /// <returns> - /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components. - /// </returns> - public readonly Vector2i PosMod(Vector2i modv) - { - Vector2i v = this; - v.x = Mathf.PosMod(v.x, modv.x); - v.y = Mathf.PosMod(v.y, modv.y); - return v; - } - - /// <summary> /// Returns a vector with each component set to one or negative one, depending /// on the signs of this vector's components, or zero if the component is zero, /// by calling <see cref="Mathf.Sign(int)"/> on each component. @@ -287,16 +181,6 @@ namespace Godot return v; } - /// <summary> - /// Returns a perpendicular vector rotated 90 degrees counter-clockwise - /// compared to the original, with the same length. - /// </summary> - /// <returns>The perpendicular vector.</returns> - public readonly Vector2i Orthogonal() - { - return new Vector2i(y, -x); - } - // Constants private static readonly Vector2i _zero = new Vector2i(0, 0); private static readonly Vector2i _one = new Vector2i(1, 1); @@ -467,7 +351,7 @@ namespace Godot /// with the components of the given <see langword="int"/>. /// This operation uses truncated division, which is often not desired /// as it does not work well with negative numbers. - /// Consider using <see cref="PosMod(int)"/> instead + /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead /// if you want to handle negative numbers. /// </summary> /// <example> @@ -490,7 +374,7 @@ namespace Godot /// with the components of the given <see cref="Vector2i"/>. /// This operation uses truncated division, which is often not desired /// as it does not work well with negative numbers. - /// Consider using <see cref="PosMod(Vector2i)"/> instead + /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead /// if you want to handle negative numbers. /// </summary> /// <example> @@ -509,34 +393,6 @@ namespace Godot } /// <summary> - /// Performs a bitwise AND operation with this <see cref="Vector2i"/> - /// and the given <see langword="int"/>. - /// </summary> - /// <param name="vec">The vector to AND with.</param> - /// <param name="and">The integer to AND with.</param> - /// <returns>The result of the bitwise AND.</returns> - public static Vector2i operator &(Vector2i vec, int and) - { - vec.x &= and; - vec.y &= and; - return vec; - } - - /// <summary> - /// Performs a bitwise AND operation with this <see cref="Vector2i"/> - /// and the given <see cref="Vector2i"/>. - /// </summary> - /// <param name="vec">The left vector to AND with.</param> - /// <param name="andv">The right vector to AND with.</param> - /// <returns>The result of the bitwise AND.</returns> - public static Vector2i operator &(Vector2i vec, Vector2i andv) - { - vec.x &= andv.x; - vec.y &= andv.y; - return vec; - } - - /// <summary> /// Returns <see langword="true"/> if the vectors are equal. /// </summary> /// <param name="left">The left vector.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 031464dcc6..b017ba5853 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -396,23 +396,6 @@ namespace Godot } /// <summary> - /// Returns the result of the linear interpolation between - /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>. - /// </summary> - /// <param name="to">The destination vector for interpolation.</param> - /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> - /// <returns>The resulting vector of the interpolation.</returns> - public readonly Vector3 Lerp(Vector3 to, Vector3 weight) - { - return new Vector3 - ( - Mathf.Lerp(x, to.x, weight.x), - Mathf.Lerp(y, to.y, weight.y), - Mathf.Lerp(z, to.z, weight.z) - ); - } - - /// <summary> /// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>. /// </summary> /// <param name="length">The length to limit to.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index e631a9f443..de0c6d27e7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -129,39 +129,6 @@ namespace Godot } /// <summary> - /// Returns the squared distance between this vector and <paramref name="to"/>. - /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if - /// you need to compare vectors or need the squared distance for some formula. - /// </summary> - /// <param name="to">The other vector to use.</param> - /// <returns>The squared distance between the two vectors.</returns> - public readonly int DistanceSquaredTo(Vector3i to) - { - return (to - this).LengthSquared(); - } - - /// <summary> - /// Returns the distance between this vector and <paramref name="to"/>. - /// </summary> - /// <seealso cref="DistanceSquaredTo(Vector3i)"/> - /// <param name="to">The other vector to use.</param> - /// <returns>The distance between the two vectors.</returns> - public readonly real_t DistanceTo(Vector3i to) - { - return (to - this).Length(); - } - - /// <summary> - /// Returns the dot product of this vector and <paramref name="with"/>. - /// </summary> - /// <param name="with">The other vector to use.</param> - /// <returns>The dot product of the two vectors.</returns> - public readonly int Dot(Vector3i with) - { - return x * with.x + y * with.y + z * with.z; - } - - /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> /// <seealso cref="LengthSquared"/> @@ -211,40 +178,6 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components - /// and <paramref name="mod"/>. - /// </summary> - /// <param name="mod">A value representing the divisor of the operation.</param> - /// <returns> - /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>. - /// </returns> - public readonly Vector3i PosMod(int mod) - { - Vector3i v = this; - v.x = Mathf.PosMod(v.x, mod); - v.y = Mathf.PosMod(v.y, mod); - v.z = Mathf.PosMod(v.z, mod); - return v; - } - - /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components - /// and <paramref name="modv"/>'s components. - /// </summary> - /// <param name="modv">A vector representing the divisors of the operation.</param> - /// <returns> - /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components. - /// </returns> - public readonly Vector3i PosMod(Vector3i modv) - { - Vector3i v = this; - v.x = Mathf.PosMod(v.x, modv.x); - v.y = Mathf.PosMod(v.y, modv.y); - v.z = Mathf.PosMod(v.z, modv.z); - return v; - } - - /// <summary> /// Returns a vector with each component set to one or negative one, depending /// on the signs of this vector's components, or zero if the component is zero, /// by calling <see cref="Mathf.Sign(int)"/> on each component. @@ -455,7 +388,7 @@ namespace Godot /// with the components of the given <see langword="int"/>. /// This operation uses truncated division, which is often not desired /// as it does not work well with negative numbers. - /// Consider using <see cref="PosMod(int)"/> instead + /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead /// if you want to handle negative numbers. /// </summary> /// <example> @@ -479,7 +412,7 @@ namespace Godot /// with the components of the given <see cref="Vector3i"/>. /// This operation uses truncated division, which is often not desired /// as it does not work well with negative numbers. - /// Consider using <see cref="PosMod(Vector3i)"/> instead + /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead /// if you want to handle negative numbers. /// </summary> /// <example> @@ -499,36 +432,6 @@ namespace Godot } /// <summary> - /// Performs a bitwise AND operation with this <see cref="Vector3i"/> - /// and the given <see langword="int"/>. - /// </summary> - /// <param name="vec">The vector to AND with.</param> - /// <param name="and">The integer to AND with.</param> - /// <returns>The result of the bitwise AND.</returns> - public static Vector3i operator &(Vector3i vec, int and) - { - vec.x &= and; - vec.y &= and; - vec.z &= and; - return vec; - } - - /// <summary> - /// Performs a bitwise AND operation with this <see cref="Vector3i"/> - /// and the given <see cref="Vector3i"/>. - /// </summary> - /// <param name="vec">The left vector to AND with.</param> - /// <param name="andv">The right vector to AND with.</param> - /// <returns>The result of the bitwise AND.</returns> - public static Vector3i operator &(Vector3i vec, Vector3i andv) - { - vec.x &= andv.x; - vec.y &= andv.y; - vec.z &= andv.z; - return vec; - } - - /// <summary> /// Returns <see langword="true"/> if the vectors are equal. /// </summary> /// <param name="left">The left vector.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs index 8146991fd7..00ecc64856 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs @@ -433,38 +433,6 @@ namespace Godot } /// <summary> - /// Performs a bitwise AND operation with this <see cref="Vector4i"/> - /// and the given <see langword="int"/>. - /// </summary> - /// <param name="vec">The vector to AND with.</param> - /// <param name="and">The integer to AND with.</param> - /// <returns>The result of the bitwise AND.</returns> - public static Vector4i operator &(Vector4i vec, int and) - { - vec.x &= and; - vec.y &= and; - vec.z &= and; - vec.w &= and; - return vec; - } - - /// <summary> - /// Performs a bitwise AND operation with this <see cref="Vector4i"/> - /// and the given <see cref="Vector4i"/>. - /// </summary> - /// <param name="vec">The left vector to AND with.</param> - /// <param name="andv">The right vector to AND with.</param> - /// <returns>The result of the bitwise AND.</returns> - public static Vector4i operator &(Vector4i vec, Vector4i andv) - { - vec.x &= andv.x; - vec.y &= andv.y; - vec.z &= andv.z; - vec.w &= andv.w; - return vec; - } - - /// <summary> /// Returns <see langword="true"/> if the vectors are equal. /// </summary> /// <param name="left">The left vector.</param> diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index 9b071ecc02..9e542828ee 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -172,7 +172,7 @@ ReplicationEditor::ReplicationEditor() { set_custom_minimum_size(Size2(0, 200) * EDSCALE); delete_dialog = memnew(ConfirmationDialog); - delete_dialog->connect("cancelled", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(false)); + delete_dialog->connect("canceled", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(false)); delete_dialog->connect("confirmed", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(true)); add_child(delete_dialog); @@ -250,14 +250,12 @@ ReplicationEditor::ReplicationEditor() { tree->add_child(drop_label); drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); - tree->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_CDU(tree, ReplicationEditor); } void ReplicationEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_config"), &ReplicationEditor::_update_config); ClassDB::bind_method(D_METHOD("_update_checked", "property", "column", "checked"), &ReplicationEditor::_update_checked); - ClassDB::bind_method("_can_drop_data_fw", &ReplicationEditor::_can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &ReplicationEditor::_drop_data_fw); } bool ReplicationEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp index 7ed69a84d0..0aa54b69f9 100644 --- a/modules/multiplayer/multiplayer_spawner.cpp +++ b/modules/multiplayer/multiplayer_spawner.cpp @@ -199,10 +199,6 @@ void MultiplayerSpawner::_notification(int p_what) { Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E.key)); ERR_CONTINUE(!node); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit)); - // This is unlikely, but might still crash the engine. - if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready))) { - node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready)); - } get_multiplayer()->object_configuration_remove(node, this); } tracked_nodes.clear(); @@ -244,11 +240,11 @@ void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_s if (!tracked_nodes.has(oid)) { tracked_nodes[oid] = SpawnInfo(p_argument.duplicate(true), p_scene_id); p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT); - p_node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT); + _spawn_notify(p_node->get_instance_id()); } } -void MultiplayerSpawner::_node_ready(ObjectID p_id) { +void MultiplayerSpawner::_spawn_notify(ObjectID p_id) { get_multiplayer()->object_configuration_add(ObjectDB::get_instance(p_id), this); } diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h index 8d401a6818..8a54140e32 100644 --- a/modules/multiplayer/multiplayer_spawner.h +++ b/modules/multiplayer/multiplayer_spawner.h @@ -77,7 +77,7 @@ private: void _track(Node *p_node, const Variant &p_argument, int p_scene_id = INVALID_ID); void _node_added(Node *p_node); void _node_exit(ObjectID p_id); - void _node_ready(ObjectID p_id); + void _spawn_notify(ObjectID p_id); Vector<String> _get_spawnable_scenes() const; void _set_spawnable_scenes(const Vector<String> &p_scenes); diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index e1b7b0c346..3466cb10df 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -125,6 +125,20 @@ void SceneReplicationInterface::on_reset() { } void SceneReplicationInterface::on_network_process() { + // Prevent endless stalling in case of unforeseen spawn errors. + if (spawn_queue.size()) { + ERR_PRINT("An error happened during last spawn, this usually means the 'ready' signal was not emitted by the spawned node."); + for (const ObjectID &oid : spawn_queue) { + Node *node = get_id_as<Node>(oid); + ERR_CONTINUE(!node); + if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready))) { + node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready)); + } + } + spawn_queue.clear(); + } + + // Process timed syncs. uint64_t msec = OS::get_singleton()->get_ticks_msec(); for (KeyValue<int, PeerInfo> &E : peers_info) { const HashSet<ObjectID> to_sync = E.value.sync_nodes; @@ -144,17 +158,39 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) { // Track node. const ObjectID oid = node->get_instance_id(); TrackedNode &tobj = _track(oid); + + // Spawn state needs to be callected after "ready", but the spawn order follows "enter_tree". ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); tobj.spawner = spawner->get_instance_id(); - spawned_nodes.insert(oid); + spawn_queue.insert(oid); + node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready).bind(oid), Node::CONNECT_ONE_SHOT); + return OK; +} + +void SceneReplicationInterface::_node_ready(const ObjectID &p_oid) { + ERR_FAIL_COND(!spawn_queue.has(p_oid)); // Bug. - if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) { - if (tobj.net_id == 0) { - tobj.net_id = ++last_net_id; + // If we are a nested spawn, we need to wait until the parent is ready. + if (p_oid != *(spawn_queue.begin())) { + return; + } + + for (const ObjectID &oid : spawn_queue) { + ERR_CONTINUE(!tracked_nodes.has(oid)); + + TrackedNode &tobj = tracked_nodes[oid]; + MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tobj.spawner); + ERR_CONTINUE(!spawner); + + spawned_nodes.insert(oid); + if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) { + if (tobj.net_id == 0) { + tobj.net_id = ++last_net_id; + } + _update_spawn_visibility(0, oid); } - _update_spawn_visibility(0, oid); } - return OK; + spawn_queue.clear(); } Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) { diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h index a5e610cff6..cf45db2138 100644 --- a/modules/multiplayer/scene_replication_interface.h +++ b/modules/multiplayer/scene_replication_interface.h @@ -51,7 +51,6 @@ private: bool operator==(const ObjectID &p_other) { return id == p_other; } - _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) { @@ -75,7 +74,10 @@ private: HashSet<ObjectID> spawned_nodes; HashSet<ObjectID> sync_nodes; - // Pending spawn information. + // Pending local spawn information (handles spawning nested nodes during ready). + HashSet<ObjectID> spawn_queue; + + // Pending remote spawn information. ObjectID pending_spawn; int pending_spawn_remote = 0; const uint8_t *pending_buffer = nullptr; @@ -89,6 +91,7 @@ private: TrackedNode &_track(const ObjectID &p_id); void _untrack(const ObjectID &p_id); + void _node_ready(const ObjectID &p_oid); 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); diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp index 54f7abda8d..557d45b386 100644 --- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp @@ -60,12 +60,40 @@ void NavigationMeshEditor::_bake_pressed() { button_bake->set_pressed(false); ERR_FAIL_COND(!node); - if (!node->get_navigation_mesh().is_valid()) { + Ref<NavigationMesh> navmesh = node->get_navigation_mesh(); + if (!navmesh.is_valid()) { err_dialog->set_text(TTR("A NavigationMesh resource must be set or created for this node to work.")); err_dialog->popup_centered(); return; } + String path = navmesh->get_path(); + if (!path.is_resource_file()) { + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + err_dialog->set_text(TTR("Cannot generate navigation mesh because it does not belong to the edited scene. Make it unique first.")); + err_dialog->popup_centered(); + return; + } + } else { + if (FileAccess::exists(base + ".import")) { + err_dialog->set_text(TTR("Cannot generate navigation mesh because it belongs to a resource which was imported.")); + err_dialog->popup_centered(); + return; + } + } + } + } else { + if (FileAccess::exists(path + ".import")) { + err_dialog->set_text(TTR("Cannot generate navigation mesh because the resource was imported from another type.")); + err_dialog->popup_centered(); + return; + } + } + NavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh()); NavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node); diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 9b5d78d465..2b5db6462c 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -731,24 +731,21 @@ COMMAND_1(free, RID, p_object) { NavMap *map = map_owner.get_or_null(p_object); // Removes any assigned region - LocalVector<NavRegion *> regions = map->get_regions(); - for (uint32_t i = 0; i < regions.size(); i++) { - map->remove_region(regions[i]); - regions[i]->set_map(nullptr); + for (NavRegion *region : map->get_regions()) { + map->remove_region(region); + region->set_map(nullptr); } // Removes any assigned links - LocalVector<NavLink *> links = map->get_links(); - for (uint32_t i = 0; i < links.size(); i++) { - map->remove_link(links[i]); - links[i]->set_map(nullptr); + for (NavLink *link : map->get_links()) { + map->remove_link(link); + link->set_map(nullptr); } // Remove any assigned agent - LocalVector<RvoAgent *> agents = map->get_agents(); - for (uint32_t i = 0; i < agents.size(); i++) { - map->remove_agent(agents[i]); - agents[i]->set_map(nullptr); + for (RvoAgent *agent : map->get_agents()) { + map->remove_agent(agent); + agent->set_map(nullptr); } int map_index = active_maps.find(map); @@ -806,9 +803,9 @@ void GodotNavigationServer::flush_queries() { MutexLock lock(commands_mutex); MutexLock lock2(operations_mutex); - for (size_t i(0); i < commands.size(); i++) { - commands[i]->exec(this); - memdelete(commands[i]); + for (SetCommand *command : commands) { + command->exec(this); + memdelete(command); } commands.clear(); } diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index fd735f8793..fe255c1ce8 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -103,9 +103,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p float begin_d = 1e20; float end_d = 1e20; // Find the initial poly and the end poly on this map. - for (size_t i(0); i < polygons.size(); i++) { - const gd::Polygon &p = polygons[i]; - + for (const gd::Polygon &p : polygons) { // Only consider the polygon if it in a region with compatible layers. if ((p_navigation_layers & p.owner->get_navigation_layers()) == 0) { continue; @@ -190,9 +188,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p 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++) { - const gd::Edge &edge = navigation_polys[least_cost_id].poly->edges[i]; - + for (const gd::Edge &edge : navigation_polys[least_cost_id].poly->edges) { // 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++) { const gd::Edge::Connection &connection = edge.connections[connection_index]; @@ -229,7 +225,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p avp.entry = new_entry; } } else { - // Add the neighbour polygon to the reachable ones. + // Add the neighbor polygon to the reachable ones. gd::NavigationPoly new_navigation_poly = gd::NavigationPoly(connection.polygon); new_navigation_poly.self_id = navigation_polys.size(); new_navigation_poly.back_navigation_poly_id = least_cost_id; @@ -240,7 +236,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p new_navigation_poly.entry = new_entry; navigation_polys.push_back(new_navigation_poly); - // Add the neighbour polygon to the polygons to visit. + // Add the neighbor polygon to the polygons to visit. to_visit.push_back(navigation_polys.size() - 1); } } @@ -465,9 +461,7 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector Vector3 closest_point; real_t closest_point_d = 1e20; - for (size_t i(0); i < polygons.size(); i++) { - const gd::Polygon &p = polygons[i]; - + for (const gd::Polygon &p : polygons) { // For each face check the distance to the segment for (size_t point_id = 2; point_id < p.points.size(); point_id += 1) { const Face3 f(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos); @@ -623,20 +617,20 @@ void NavMap::sync() { // Check if we need to update the links. if (regenerate_polygons) { - for (uint32_t r = 0; r < regions.size(); r++) { - regions[r]->scratch_polygons(); + for (NavRegion *region : regions) { + region->scratch_polygons(); } regenerate_links = true; } - for (uint32_t r = 0; r < regions.size(); r++) { - if (regions[r]->sync()) { + for (NavRegion *region : regions) { + if (region->sync()) { regenerate_links = true; } } - for (uint32_t l = 0; l < links.size(); l++) { - if (links[l]->check_dirty()) { + for (NavLink *link : links) { + if (link->check_dirty()) { regenerate_links = true; } } @@ -649,34 +643,32 @@ void NavMap::sync() { _new_pm_edge_free_count = 0; // Remove regions connections. - for (uint32_t r = 0; r < regions.size(); r++) { - regions[r]->get_connections().clear(); + for (NavRegion *region : regions) { + region->get_connections().clear(); } // Resize the polygon count. int count = 0; - for (uint32_t r = 0; r < regions.size(); r++) { - count += regions[r]->get_polygons().size(); + for (const NavRegion *region : regions) { + count += region->get_polygons().size(); } polygons.resize(count); // Copy all region polygons in the map. count = 0; - for (uint32_t r = 0; r < regions.size(); r++) { - const LocalVector<gd::Polygon> &polygons_source = regions[r]->get_polygons(); + for (const NavRegion *region : regions) { + const LocalVector<gd::Polygon> &polygons_source = region->get_polygons(); for (uint32_t n = 0; n < polygons_source.size(); n++) { polygons[count + n] = polygons_source[n]; } - count += regions[r]->get_polygons().size(); + count += region->get_polygons().size(); } _new_pm_polygon_count = polygons.size(); // Group all edges per key. HashMap<gd::EdgeKey, Vector<gd::Edge::Connection>, gd::EdgeKey> connections; - for (uint32_t poly_id = 0; poly_id < polygons.size(); poly_id++) { - gd::Polygon &poly(polygons[poly_id]); - + for (gd::Polygon &poly : polygons) { for (uint32_t p = 0; p < poly.points.size(); p++) { int next_point = (p + 1) % poly.points.size(); gd::EdgeKey ek(poly.points[p].key, poly.points[next_point].key); @@ -787,8 +779,7 @@ void NavMap::sync() { link_polygons.resize(links.size()); // Search for polygons within range of a nav link. - for (uint32_t l = 0; l < links.size(); l++) { - const NavLink *link = links[l]; + for (const NavLink *link : links) { const Vector3 start = link->get_start_location(); const Vector3 end = link->get_end_location(); @@ -820,9 +811,7 @@ void NavMap::sync() { } // Find any polygons within the search radius of the end point. - for (uint32_t end_index = 0; end_index < polygons.size(); end_index++) { - gd::Polygon &end_poly = polygons[end_index]; - + for (gd::Polygon &end_poly : polygons) { // For each face check the distance to the end for (uint32_t end_point_id = 2; end_point_id < end_poly.points.size(); end_point_id += 1) { const Face3 end_face(end_poly.points[0].pos, end_poly.points[end_point_id - 1].pos, end_poly.points[end_point_id].pos); @@ -906,8 +895,8 @@ void NavMap::sync() { // cannot use LocalVector here as RVO library expects std::vector to build KdTree std::vector<RVO::Agent *> raw_agents; raw_agents.reserve(agents.size()); - for (size_t i(0); i < agents.size(); i++) { - raw_agents.push_back(agents[i]->get_agent()); + for (RvoAgent *agent : agents) { + raw_agents.push_back(agent->get_agent()); } rvo.buildAgentTree(raw_agents); } @@ -941,8 +930,8 @@ void NavMap::step(real_t p_deltatime) { } void NavMap::dispatch_callbacks() { - for (int i(0); i < static_cast<int>(controlled_agents.size()); i++) { - controlled_agents[i]->dispatch_callback(); + for (RvoAgent *agent : controlled_agents) { + agent->dispatch_callback(); } } diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index fff7a02fc4..74ff9312fd 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -266,9 +266,7 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans if (err == OK) { PackedVector3Array faces; - for (uint32_t j = 0; j < md.faces.size(); ++j) { - const Geometry3D::MeshData::Face &face = md.faces[j]; - + for (const Geometry3D::MeshData::Face &face : md.faces) { for (uint32_t k = 2; k < face.indices.size(); ++k) { faces.push_back(md.vertices[face.indices[0]]); faces.push_back(md.vertices[face.indices[k - 1]]); @@ -392,9 +390,7 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans if (err == OK) { PackedVector3Array faces; - for (uint32_t j = 0; j < md.faces.size(); ++j) { - const Geometry3D::MeshData::Face &face = md.faces[j]; - + for (const Geometry3D::MeshData::Face &face : md.faces) { for (uint32_t k = 2; k < face.indices.size(); ++k) { faces.push_back(md.vertices[face.indices[0]]); faces.push_back(md.vertices[face.indices[k - 1]]); diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp index 0acaaf5fc9..d473f3b4a0 100644 --- a/modules/ogg/ogg_packet_sequence.cpp +++ b/modules/ogg/ogg_packet_sequence.cpp @@ -136,6 +136,8 @@ bool OggPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const { ERR_FAIL_COND_V(data_version != ogg_packet_sequence->data_version, false); ERR_FAIL_COND_V(ogg_packet_sequence->page_data.is_empty(), false); ERR_FAIL_COND_V(ogg_packet_sequence->page_granule_positions.is_empty(), false); + ERR_FAIL_COND_V(page_cursor >= ogg_packet_sequence->page_data.size(), false); + // Move on to the next page if need be. This happens first to help simplify seek logic. while (packet_cursor >= ogg_packet_sequence->page_data[page_cursor].size()) { packet_cursor = 0; diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml index a3a45ebb4c..d53648723a 100644 --- a/modules/openxr/doc_classes/OpenXRAction.xml +++ b/modules/openxr/doc_classes/OpenXRAction.xml @@ -5,7 +5,7 @@ </brief_description> <description> This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics). - OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully. + OpenXR performs automatic conversion between action type and input type whenever possible. An analog trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully. Actions are not directly bound to specific devices, instead OpenXR recognizes a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths. Note that the name of the resource is used to register the action with. </description> @@ -27,7 +27,7 @@ This action provides a boolean value. </constant> <constant name="OPENXR_ACTION_FLOAT" value="1" enum="ActionType"> - This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analogue input such as triggers. + This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analog input such as triggers. </constant> <constant name="OPENXR_ACTION_VECTOR2" value="2" enum="ActionType"> This action provides a vector2 value and can be bound to embedded trackpads and joysticks diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp index 6ce8f0805f..0d201161f1 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/openxr_opengl_extension.cpp @@ -158,12 +158,14 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) { p_usable_swap_chains.push_back(GL_RGBA8); + p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8); } void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) { p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT32F); p_usable_depth_formats.push_back(GL_DEPTH24_STENCIL8); p_usable_depth_formats.push_back(GL_DEPTH32F_STENCIL8); + p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT24); } bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) { diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index d556f475d2..0a25cd68b7 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -560,6 +560,12 @@ void OpenXRAPI::destroy_instance() { instance = XR_NULL_HANDLE; } enabled_extensions.clear(); + + if (graphics_extension != nullptr) { + unregister_extension_wrapper(graphics_extension); + memdelete(graphics_extension); + graphics_extension = nullptr; + } } bool OpenXRAPI::create_session() { @@ -745,7 +751,7 @@ bool OpenXRAPI::create_swapchains() { Also Godot only creates a swapchain for the main output. OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system - to optimise text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're + to optimize text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're already rendering the next frame. Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create, @@ -1347,6 +1353,10 @@ void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_w registered_extension_wrappers.push_back(p_extension_wrapper); } +void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) { + registered_extension_wrappers.erase(p_extension_wrapper); +} + void OpenXRAPI::register_extension_metadata() { for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { extension_wrapper->on_register_metadata(); diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 5fb8de660e..e1787c6da0 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -53,7 +53,7 @@ #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. +// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initializing 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. // forward declarations, we don't want to include these fully @@ -312,6 +312,7 @@ public: void set_xr_interface(OpenXRInterface *p_xr_interface); static void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper); + static void unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper); static void register_extension_metadata(); static void cleanup_extension_wrappers(); diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 4e2fe3dab5..306a2f1bbd 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -70,7 +70,7 @@ static void _editor_init() { // Only add our OpenXR action map editor if OpenXR is enabled for our project if (openxr_interaction_profile_meta_data == nullptr) { - // If we didn't initialize our actionmap meta data at startup, we initialise it now. + // If we didn't initialize our actionmap meta data at startup, we initialize it now. openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData); ERR_FAIL_NULL(openxr_interaction_profile_meta_data); } @@ -85,7 +85,7 @@ static void _editor_init() { void initialize_openxr_module(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { if (OpenXRAPI::openxr_is_enabled(false)) { - // Always register our extension wrappers even if we don't initialise OpenXR. + // Always register our extension wrappers even if we don't initialize OpenXR. // Some of these wrappers will add functionality to our editor. #ifdef ANDROID_ENABLED OpenXRAPI::register_extension_wrapper(memnew(OpenXRAndroidExtension)); @@ -111,6 +111,10 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { ERR_FAIL_NULL(openxr_api); if (!openxr_api->initialize(Main::get_rendering_driver_name())) { + OS::get_singleton()->alert("OpenXR was requested but failed to start.\n" + "Please check if your HMD is connected.\n" + "When using Windows MR please note that WMR only has DirectX support, make sure SteamVR is your default OpenXR runtime.\n" + "Godot will start in normal mode.\n"); memdelete(openxr_api); openxr_api = nullptr; return; diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index c74799caa3..9394f71e40 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -426,8 +426,8 @@ bool RaycastOcclusionCull::Scenario::update() { return false; } - for (unsigned int i = 0; i < removed_instances.size(); i++) { - instances.erase(removed_instances[i]); + for (const RID &scenario : removed_instances) { + instances.erase(scenario); } if (dirty_instances_array.size() / WorkerThreadPool::get_singleton()->get_thread_count() > 128) { diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index e52b87741e..ddafae5e58 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -423,11 +423,7 @@ 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); @@ -476,11 +472,7 @@ 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 @@ -824,29 +816,17 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ // Could not find texture to fit, create one. int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); -#ifdef GDEXTENSION - texsize = Math::next_power_of_2(texsize); -#else texsize = next_power_of_2(texsize); -#endif if (p_msdf) { texsize = MIN(texsize, 2048); } else { texsize = MIN(texsize, 1024); } if (mw > texsize) { // Special case, adapt to it? -#ifdef GDEXTENSION - texsize = Math::next_power_of_2(mw); -#else texsize = next_power_of_2(mw); -#endif } if (mh > texsize) { // Special case, adapt to it? -#ifdef GDEXTENSION - texsize = Math::next_power_of_2(mh); -#else texsize = next_power_of_2(mh); -#endif } ShelfPackTexture tex = ShelfPackTexture(texsize, texsize); @@ -949,14 +929,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con return 0; } -void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const { +void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) { MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td); msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape); - int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y; + int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y; for (int col = 0; col < td->output->width(); ++col) { - int x = (y % 2) ? td->output->width() - col - 1 : col; - msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5)); + int x = (p_y % 2) ? td->output->width() - col - 1 : col; + msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5)); msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p); td->distancePixelConversion->operator()(td->output->operator()(x, row), distance); } @@ -1026,14 +1006,8 @@ _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::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF")); WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); -#endif msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); @@ -3680,6 +3654,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) { RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction."); ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced); sd->hb_buffer = hb_buffer_create(); @@ -3705,6 +3680,7 @@ void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) { 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_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction."); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -3764,8 +3740,12 @@ void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, con } sd->bidi_override.clear(); for (int i = 0; i < p_override.size(); i++) { - if (p_override[i].get_type() == Variant::VECTOR2I) { - sd->bidi_override.push_back(p_override[i]); + if (p_override[i].get_type() == Variant::VECTOR3I) { + const Vector3i &r = p_override[i]; + sd->bidi_override.push_back(r); + } else if (p_override[i].get_type() == Variant::VECTOR2I) { + const Vector2i &r = p_override[i]; + sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED)); } } invalidate(sd, false); @@ -4156,8 +4136,9 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S if (p_sd->bidi_override[ov].x >= p_start + p_length || p_sd->bidi_override[ov].y <= p_start) { continue; } - int start = _convert_pos_inv(p_sd, MAX(0, p_start - p_sd->bidi_override[ov].x)); - int end = _convert_pos_inv(p_sd, MIN(p_start + p_length, p_sd->bidi_override[ov].y) - p_sd->bidi_override[ov].x); + int ov_start = _convert_pos_inv(p_sd, p_sd->bidi_override[ov].x); + int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start); + int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, p_sd->bidi_override[ov].y)) - ov_start; ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range."); @@ -4179,8 +4160,8 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S int32_t _bidi_run_length = 0; ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length); - int32_t bidi_run_start = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start); - int32_t bidi_run_end = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length); + int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start); + int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length); for (int j = 0; j < sd_size; j++) { if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) { @@ -5570,8 +5551,31 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length())); } + int base_para_direction = UBIDI_DEFAULT_LTR; + switch (sd->direction) { + case DIRECTION_LTR: { + sd->para_direction = DIRECTION_LTR; + base_para_direction = UBIDI_LTR; + } break; + case DIRECTION_RTL: { + sd->para_direction = DIRECTION_RTL; + base_para_direction = UBIDI_RTL; + } break; + case DIRECTION_INHERITED: + case DIRECTION_AUTO: { + UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length()); + if (direction != UBIDI_NEUTRAL) { + sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR; + base_para_direction = direction; + } else { + sd->para_direction = DIRECTION_LTR; + base_para_direction = UBIDI_DEFAULT_LTR; + } + } break; + } + if (sd->bidi_override.is_empty()) { - sd->bidi_override.push_back(Vector2i(sd->start, sd->end)); + sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED)); } for (int ov = 0; ov < sd->bidi_override.size(); ov++) { @@ -5584,26 +5588,25 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { } UErrorCode err = U_ZERO_ERROR; - UBiDi *bidi_iter = ubidi_openSized(end, 0, &err); + UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err); ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err)); - switch (sd->direction) { + switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) { case DIRECTION_LTR: { ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err); - sd->para_direction = DIRECTION_LTR; } break; case DIRECTION_RTL: { ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err); - sd->para_direction = DIRECTION_RTL; + } break; + case DIRECTION_INHERITED: { + ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err); } break; case DIRECTION_AUTO: { UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start); if (direction != UBIDI_NEUTRAL) { ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err); - sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR; } else { - ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err); - sd->para_direction = DIRECTION_LTR; + ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err); } } break; } @@ -5635,8 +5638,8 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { } } - int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start); - int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start + _bidi_run_length); + int32_t bidi_run_start = _convert_pos(sd, start + _bidi_run_start); + int32_t bidi_run_end = _convert_pos(sd, start + _bidi_run_start + _bidi_run_length); // Shape runs. diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index e8a3a10ab8..c7fe46d554 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -72,7 +72,6 @@ #include <godot_cpp/templates/hash_map.hpp> #include <godot_cpp/templates/hash_set.hpp> #include <godot_cpp/templates/rid_owner.hpp> - #include <godot_cpp/templates/vector.hpp> using namespace godot; @@ -350,7 +349,7 @@ class TextServerAdvanced : public TextServerExtension { _FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const; _FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const; _FORCE_INLINE_ void _font_clear_cache(FontAdvanced *p_font_data); - void _generateMTSDF_threaded(uint32_t y, void *p_td) const; + static void _generateMTSDF_threaded(void *p_td, uint32_t p_y); _FORCE_INLINE_ Vector2i _get_size(const FontAdvanced *p_font_data, int p_size) const { if (p_font_data->msdf) { @@ -500,7 +499,7 @@ class TextServerAdvanced : public TextServerExtension { /* Intermediate data */ Char16String utf16; Vector<UBiDi *> bidi_iter; - Vector<Vector2i> bidi_override; + Vector<Vector3i> bidi_override; ScriptIterator *script_iter = nullptr; hb_buffer_t *hb_buffer = nullptr; diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp index 9354d3f9b3..1406e3aaa0 100644 --- a/modules/text_server_adv/thorvg_svg_in_ot.cpp +++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp @@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin if (!gl_state.ready) { Ref<XMLParser> parser; parser.instantiate(); -#ifdef GDEXTENSION - PackedByteArray data; - data.resize(document->svg_document_length); - memcpy(data.ptrw(), document->svg_document, document->svg_document_length); - parser->open_buffer(data); -#else parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length); -#endif float aspect = 1.0f; String xml_body; while (parser->read() == OK) { if (parser->has_attribute("id")) { -#ifdef GDEXTENSION const String &gl_name = parser->get_named_attribute_value("id"); -#else - const String &gl_name = parser->get_attribute_value("id"); -#endif if (gl_name.begins_with("glyph")) { int dot_pos = gl_name.find("."); int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int(); @@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin } if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") { if (parser->has_attribute("viewBox")) { -#ifdef GDEXTENSION PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" "); -#else - Vector<String> vb = parser->get_attribute_value("viewBox").split(" "); -#endif if (vb.size() == 4) { aspect = vb[2].to_float() / vb[3].to_float(); @@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin } continue; } -#ifdef GDEXTENSION - if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { - xml_body = xml_body + "<" + parser->get_node_name(); - for (int i = 0; i < parser->get_attribute_count(); i++) { - xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\""; - } - xml_body = xml_body + ">"; - } else if (parser->get_node_type() == XMLParser::NODE_TEXT) { - xml_body = xml_body + parser->get_node_data(); - } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { - xml_body = xml_body + "</" + parser->get_node_name() + ">"; - } -#else if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { xml_body += vformat("<%s", parser->get_node_name()); for (int i = 0; i < parser->get_attribute_count(); i++) { @@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { xml_body += vformat("</%s>", parser->get_node_name()); } -#endif } String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body; @@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin new_h = (new_w / aspect); } -#ifdef GDEXTENSION gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body; -#else - gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body; -#endif picture = tvg::Picture::gen(); result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 034f88e387..b5d7d3a3cf 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -51,7 +51,6 @@ using namespace godot; #include "core/error/error_macros.h" #include "core/string/print_string.h" #include "core/string/translation.h" -#include "core/string/ucaps.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. @@ -248,11 +247,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ // Could not find texture to fit, create one. int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); -#ifdef GDEXTENSION - texsize = Math::next_power_of_2(texsize); -#else texsize = next_power_of_2(texsize); -#endif if (p_msdf) { texsize = MIN(texsize, 2048); @@ -260,18 +255,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_ texsize = MIN(texsize, 1024); } if (mw > texsize) { // Special case, adapt to it? -#ifdef GDEXTENSION - texsize = Math::next_power_of_2(mw); -#else texsize = next_power_of_2(mw); -#endif } if (mh > texsize) { // Special case, adapt to it? -#ifdef GDEXTENSION - texsize = Math::next_power_of_2(mh); -#else texsize = next_power_of_2(mh); -#endif } ShelfPackTexture tex = ShelfPackTexture(texsize, texsize); @@ -374,14 +361,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con return 0; } -void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const { +void TextServerFallback::_generateMTSDF_threaded(void *p_td, uint32_t p_y) { MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td); msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape); - int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y; + int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y; for (int col = 0; col < td->output->width(); ++col) { - int x = (y % 2) ? td->output->width() - col - 1 : col; - msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5)); + int x = (p_y % 2) ? td->output->width() - col - 1 : col; + msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5)); msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p); td->distancePixelConversion->operator()(td->output->operator()(x, row), distance); } @@ -451,14 +438,8 @@ _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 + WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, String("TextServerFBRenderMSDF")); + WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); @@ -2683,6 +2664,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) { RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction."); ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback); sd->direction = p_direction; @@ -2706,6 +2688,7 @@ void TextServerFallback::_shaped_text_clear(const RID &p_shaped) { } void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { + ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction."); if (p_direction == DIRECTION_RTL) { ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server."); } @@ -4078,31 +4061,11 @@ double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_sha } 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++) { - const char32_t s = upper[i]; - const char32_t t = _find_upper(s); - if (s != t) { // avoid copy on write - upper[i] = t; - } - } - - return upper; + return p_string.to_upper(); } 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++) { - const char32_t s = lower[i]; - const char32_t t = _find_lower(s); - if (s != t) { // avoid copy on write - lower[i] = t; - } - } - - return lower; + return p_string.to_lower(); } PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const { diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index b42f564534..9fb048a581 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -67,11 +67,11 @@ #include <godot_cpp/classes/image.hpp> #include <godot_cpp/classes/image_texture.hpp> #include <godot_cpp/classes/ref.hpp> +#include <godot_cpp/classes/worker_thread_pool.hpp> #include <godot_cpp/templates/hash_map.hpp> #include <godot_cpp/templates/hash_set.hpp> #include <godot_cpp/templates/rid_owner.hpp> -#include <godot_cpp/templates/thread_work_pool.hpp> #include <godot_cpp/templates/vector.hpp> using namespace godot; @@ -303,7 +303,7 @@ class TextServerFallback : public TextServerExtension { _FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const; _FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const; _FORCE_INLINE_ void _font_clear_cache(FontFallback *p_font_data); - void _generateMTSDF_threaded(uint32_t y, void *p_td) const; + static void _generateMTSDF_threaded(void *p_td, uint32_t p_y); _FORCE_INLINE_ Vector2i _get_size(const FontFallback *p_font_data, int p_size) const { if (p_font_data->msdf) { diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp index 9354d3f9b3..1406e3aaa0 100644 --- a/modules/text_server_fb/thorvg_svg_in_ot.cpp +++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp @@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin if (!gl_state.ready) { Ref<XMLParser> parser; parser.instantiate(); -#ifdef GDEXTENSION - PackedByteArray data; - data.resize(document->svg_document_length); - memcpy(data.ptrw(), document->svg_document, document->svg_document_length); - parser->open_buffer(data); -#else parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length); -#endif float aspect = 1.0f; String xml_body; while (parser->read() == OK) { if (parser->has_attribute("id")) { -#ifdef GDEXTENSION const String &gl_name = parser->get_named_attribute_value("id"); -#else - const String &gl_name = parser->get_attribute_value("id"); -#endif if (gl_name.begins_with("glyph")) { int dot_pos = gl_name.find("."); int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int(); @@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin } if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") { if (parser->has_attribute("viewBox")) { -#ifdef GDEXTENSION PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" "); -#else - Vector<String> vb = parser->get_attribute_value("viewBox").split(" "); -#endif if (vb.size() == 4) { aspect = vb[2].to_float() / vb[3].to_float(); @@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin } continue; } -#ifdef GDEXTENSION - if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { - xml_body = xml_body + "<" + parser->get_node_name(); - for (int i = 0; i < parser->get_attribute_count(); i++) { - xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\""; - } - xml_body = xml_body + ">"; - } else if (parser->get_node_type() == XMLParser::NODE_TEXT) { - xml_body = xml_body + parser->get_node_data(); - } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { - xml_body = xml_body + "</" + parser->get_node_name() + ">"; - } -#else if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { xml_body += vformat("<%s", parser->get_node_name()); for (int i = 0; i < parser->get_attribute_count(); i++) { @@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { xml_body += vformat("</%s>", parser->get_node_name()); } -#endif } String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body; @@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin new_h = (new_w / aspect); } -#ifdef GDEXTENSION gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body; -#else - gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body; -#endif picture = tvg::Picture::gen(); result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false); diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 780ad4334e..6b3bdb7fe6 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -466,14 +466,15 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() { DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) { DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error)); if (r_error != OK) { - OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver"); if (p_rendering_driver == "vulkan") { - OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" - "Please try exporting your game using the gl_compatibility renderer.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your device seems not to support the required Vulkan version.\n\n" + "Please try exporting your game using the 'gl_compatibility' renderer.", + "Unable to initialize Vulkan video driver"); } else { - OS::get_singleton()->alert("Your video card driver does not support OpenGL ES 3.0.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your device seems not to support the required OpenGL ES 3.0 version.", + "Unable to initialize OpenGL video driver"); } } return ds; diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index bb1ad3d83b..587caf81bf 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -437,6 +437,14 @@ String EditorExportPlatformAndroid::get_project_name(const String &p_name) const String EditorExportPlatformAndroid::get_package_name(const String &p_package) const { String pname = p_package; + String name = get_valid_basename(); + pname = pname.replace("$genname", name); + return pname; +} + +// Returns the project name without invalid characters +// or the "noname" string if all characters are invalid. +String EditorExportPlatformAndroid::get_valid_basename() const { String basename = GLOBAL_GET("application/config/name"); basename = basename.to_lower(); @@ -452,13 +460,12 @@ String EditorExportPlatformAndroid::get_package_name(const String &p_package) co first = false; } } + if (name.is_empty()) { name = "noname"; } - pname = pname.replace("$genname", name); - - return pname; + return name; } String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const { @@ -466,7 +473,7 @@ String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportP } bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const { - String pname = p_package; + String pname = get_package_name(p_package); if (pname.length() == 0) { if (r_error) { @@ -525,6 +532,24 @@ bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, return false; } + if (p_package.find("$genname") >= 0 && !is_project_name_valid()) { + if (r_error) { + *r_error = TTR("The project name does not meet the requirement for the package name format. Please explicitly specify the package name."); + } + return false; + } + + return true; +} + +bool EditorExportPlatformAndroid::is_project_name_valid() const { + // Get the original project name and convert to lowercase. + String basename = GLOBAL_GET("application/config/name"); + basename = basename.to_lower(); + // Check if there are invalid characters. + if (basename != get_valid_basename()) { + return false; + } return true; } @@ -2286,7 +2311,7 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit String pn = p_preset->get("package/unique_name"); String pn_err; - if (!is_package_name_valid(get_package_name(pn), &pn_err)) { + if (!is_package_name_valid(pn, &pn_err)) { valid = false; err += TTR("Invalid package name:") + " " + pn_err + "\n"; } diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index a6dfc9fcb3..bff769fcba 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -91,9 +91,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String get_package_name(const String &p_package) const; + String get_valid_basename() const; + String get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const; bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const; + bool is_project_name_valid() const; static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data); diff --git a/platform/android/java/lib/res/values/strings.xml b/platform/android/java/lib/res/values/strings.xml index f5a4ab1071..7efac4ce71 100644 --- a/platform/android/java/lib/res/values/strings.xml +++ b/platform/android/java/lib/res/values/strings.xml @@ -48,7 +48,7 @@ <string name="state_failed_unlicensed">Download failed because you may not have purchased this app</string> <string name="state_failed_fetching_url">Download failed because the resources could not be found</string> <string name="state_failed_sdcard_full">Download failed because the external storage is full</string> - <string name="state_failed_cancelled">Download cancelled</string> + <string name="state_failed_cancelled">Download canceled</string> <string name="state_failed">Download failed</string> <string name="kilobytes_per_second">%1$s KB/s</string> diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java b/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java index 2cc37b627a..3ee3478fcb 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java @@ -120,7 +120,7 @@ public final class ProcessPhoenix extends Activity { /** * Checks if the current process is a temporary Phoenix Process. - * This can be used to avoid initialisation of unused resources or to prevent running code that + * This can be used to avoid initialization of unused resources or to prevent running code that * is not multi-process ready. * * @return true if the current process is a temporary Phoenix Process diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 376ed89c16..942bf0a904 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -355,20 +355,20 @@ void OS_Android::_load_system_font_config() { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { in_font_node = false; if (parser->get_node_name() == "familyset") { - int ver = parser->has_attribute("version") ? parser->get_attribute_value("version").to_int() : 0; + int ver = parser->has_attribute("version") ? parser->get_named_attribute_value("version").to_int() : 0; if (ver < 21) { ERR_PRINT(vformat("Unsupported font config version %s", ver)); break; } } else if (parser->get_node_name() == "alias") { - String name = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String(); - String to = parser->has_attribute("to") ? parser->get_attribute_value("to").strip_edges() : String(); + String name = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String(); + String to = parser->has_attribute("to") ? parser->get_named_attribute_value("to").strip_edges() : String(); if (!name.is_empty() && !to.is_empty()) { font_aliases[name] = to; } } else if (parser->get_node_name() == "family") { - fn = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String(); - String lang_code = parser->has_attribute("lang") ? parser->get_attribute_value("lang").strip_edges() : String(); + fn = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String(); + String lang_code = parser->has_attribute("lang") ? parser->get_named_attribute_value("lang").strip_edges() : String(); Vector<String> lang_codes = lang_code.split(","); for (int i = 0; i < lang_codes.size(); i++) { Vector<String> lang_code_elements = lang_codes[i].split("-"); @@ -412,9 +412,9 @@ void OS_Android::_load_system_font_config() { } } else if (parser->get_node_name() == "font") { in_font_node = true; - fb = parser->has_attribute("fallbackFor") ? parser->get_attribute_value("fallbackFor").strip_edges() : String(); - fi.weight = parser->has_attribute("weight") ? parser->get_attribute_value("weight").to_int() : 400; - fi.italic = parser->has_attribute("style") && parser->get_attribute_value("style").strip_edges() == "italic"; + fb = parser->has_attribute("fallbackFor") ? parser->get_named_attribute_value("fallbackFor").strip_edges() : String(); + fi.weight = parser->has_attribute("weight") ? parser->get_named_attribute_value("weight").to_int() : 400; + fi.italic = parser->has_attribute("style") && parser->get_named_attribute_value("style").strip_edges() == "italic"; } } if (parser->get_node_type() == XMLParser::NODE_TEXT) { diff --git a/platform/ios/detect.py b/platform/ios/detect.py index 38e62134b5..71612cf1fa 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -99,8 +99,8 @@ def configure(env: "Environment"): if env["ios_simulator"]: detect_darwin_sdk_path("iossimulator", env) - env.Append(ASFLAGS=["-mios-simulator-version-min=13.0"]) - env.Append(CCFLAGS=["-mios-simulator-version-min=13.0"]) + env.Append(ASFLAGS=["-mios-simulator-version-min=11.0"]) + env.Append(CCFLAGS=["-mios-simulator-version-min=11.0"]) env.extra_suffix = ".simulator" + env.extra_suffix else: detect_darwin_sdk_path("ios", env) @@ -153,3 +153,11 @@ def configure(env: "Environment"): if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.Prepend( + CPPPATH=[ + "$IOS_SDK_PATH/System/Library/Frameworks/OpenGLES.framework/Headers", + ] + ) diff --git a/platform/ios/display_layer.h b/platform/ios/display_layer.h index 10f42264df..e719a42cd9 100644 --- a/platform/ios/display_layer.h +++ b/platform/ios/display_layer.h @@ -33,7 +33,8 @@ @protocol DisplayLayer <NSObject> -- (void)renderDisplayLayer; +- (void)startRenderDisplayLayer; +- (void)stopRenderDisplayLayer; - (void)initializeDisplayLayer; - (void)layoutDisplayLayer; diff --git a/platform/ios/display_layer.mm b/platform/ios/display_layer.mm index 24614fea56..3129ebb276 100644 --- a/platform/ios/display_layer.mm +++ b/platform/ios/display_layer.mm @@ -60,7 +60,10 @@ - (void)layoutDisplayLayer { } -- (void)renderDisplayLayer { +- (void)startRenderDisplayLayer { +} + +- (void)stopRenderDisplayLayer { } @end @@ -76,8 +79,6 @@ } - (void)initializeDisplayLayer { - // Get our backing layer - // Configure it so that it is opaque, does not retain the contents of the backbuffer when displayed, and uses RGBA8888 color. self.opaque = YES; self.drawableProperties = [NSDictionary @@ -87,8 +88,6 @@ kEAGLDrawablePropertyColorFormat, nil]; - // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - // Create GL ES 3 context if (GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility") { context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; @@ -115,8 +114,22 @@ [self createFramebuffer]; } -- (void)renderDisplayLayer { +- (void)startRenderDisplayLayer { [EAGLContext setCurrentContext:context]; + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); +} + +- (void)stopRenderDisplayLayer { + glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); + [context presentRenderbuffer:GL_RENDERBUFFER_OES]; + +#ifdef DEBUG_ENABLED + GLenum err = glGetError(); + if (err) { + NSLog(@"DrawView: %x error", err); + } +#endif } - (void)dealloc { @@ -154,11 +167,15 @@ return NO; } + GLES3::TextureStorage::system_fbo = viewFramebuffer; + return YES; } // Clean up any buffers we have allocated. - (void)destroyFramebuffer { + GLES3::TextureStorage::system_fbo = 0; + glDeleteFramebuffersOES(1, &viewFramebuffer); viewFramebuffer = 0; glDeleteRenderbuffersOES(1, &viewRenderbuffer); diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h index dd1157f668..e03bd8cb01 100644 --- a/platform/ios/display_server_ios.h +++ b/platform/ios/display_server_ios.h @@ -47,6 +47,10 @@ #endif #endif +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" +#endif // GLES3_ENABLED + #import <Foundation/Foundation.h> #import <QuartzCore/CAMetalLayer.h> @@ -109,7 +113,7 @@ public: void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click); void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt); - void touches_cancelled(int p_idx); + void touches_canceled(int p_idx); // MARK: Keyboard @@ -216,6 +220,7 @@ public: virtual bool screen_is_kept_on() const override; void resize_window(CGSize size); + virtual void swap_buffers() override {} }; #endif // DISPLAY_SERVER_IOS_H diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index bea88a7f9b..5447dc2eed 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -55,47 +55,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode // Init TTS tts = [[TTS_IOS alloc] init]; -#if defined(GLES3_ENABLED) - // FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented - // again, - // Note that we should be checking "opengl3" as the driver, might never enable this seeing OpenGL is deprecated on iOS - // We are hardcoding the rendering_driver to "vulkan" down below - - if (rendering_driver == "opengl3") { - bool gl_initialization_error = false; - - // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - - if (RasterizerGLES3::is_viable() == OK) { - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - } else { - gl_initialization_error = true; - } - - if (gl_initialization_error) { - OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.", "Unable to initialize video driver"); - // return ERR_UNAVAILABLE; - } - - // rendering_server = memnew(RenderingServerDefault); - // // FIXME: Reimplement threaded rendering - // if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { - // rendering_server = memnew(RenderingServerWrapMT(rendering_server, - // false)); - // } - // rendering_server->init(); - // rendering_server->cursor_set_visible(false, 0); - - // reset this to what it should be, it will have been set to 0 after - // rendering_server->init() is called - // RasterizerStorageGLES3system_fbo = gl_view_base_fb; - } -#endif - #if defined(VULKAN_ENABLED) - rendering_driver = "vulkan"; - context_vulkan = nullptr; rendering_device_vulkan = nullptr; @@ -110,13 +70,14 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"]; if (!layer) { - ERR_FAIL_MSG("Failed to create iOS rendering layer."); + ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer."); } Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale(); if (context_vulkan->window_create(MAIN_WINDOW_ID, p_vsync_mode, layer, size.width, size.height) != OK) { memdelete(context_vulkan); context_vulkan = nullptr; + r_error = ERR_UNAVAILABLE; ERR_FAIL_MSG("Failed to create Vulkan window."); } @@ -127,6 +88,18 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode } #endif +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { + CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"opengl3"]; + + if (!layer) { + ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer."); + } + + RasterizerGLES3::make_current(); + } +#endif + bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); screen_set_keep_on(keep_screen_on); @@ -252,7 +225,7 @@ void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) { Input::get_singleton()->parse_input_event(p_event); } -void DisplayServerIOS::touches_cancelled(int p_idx) { +void DisplayServerIOS::touches_canceled(int p_idx) { touch_press(p_idx, -1, -1, false, false); } @@ -689,15 +662,18 @@ void DisplayServerIOS::resize_window(CGSize viewSize) { void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) - context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + if (context_vulkan) { + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + } #endif } DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) - return context_vulkan->get_vsync_mode(p_window); -#else - return DisplayServer::VSYNC_ENABLED; + if (context_vulkan) { + return context_vulkan->get_vsync_mode(p_window); + } #endif + return DisplayServer::VSYNC_ENABLED; } diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index ccd3480d11..87b599bc81 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -1572,7 +1572,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { -#if defined(MACOS_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED) bool is_execute = false; #endif @@ -1605,7 +1605,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p continue; //ignore! } found_library = true; -#if defined(MACOS_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED) is_execute = true; #endif file = file.replace(library_to_use, binary_name + ".xcframework"); @@ -1648,7 +1648,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_buffer(data.ptr(), data.size()); } -#if defined(MACOS_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED) if (is_execute) { // we need execute rights on this file chmod(file.utf8().get_data(), 0755); diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm index 1c8c578bd2..4b10f95ab8 100644 --- a/platform/ios/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -74,16 +74,20 @@ static const float earth_gravity = 9.80665; CALayer<DisplayLayer> *layer; if ([driverName isEqualToString:@"vulkan"]) { +#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR + if (@available(iOS 13, *)) { + layer = [GodotMetalLayer layer]; + } else { + return nil; + } +#else layer = [GodotMetalLayer layer]; +#endif } else if ([driverName isEqualToString:@"opengl3"]) { if (@available(iOS 13, *)) { NSLog(@"OpenGL ES is deprecated on iOS 13"); } -#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR - return nil; -#else layer = [GodotOpenGLLayer layer]; -#endif } else { return nil; } @@ -238,7 +242,7 @@ static const float earth_gravity = 9.80665; [self.displayLink setPaused:NO]; } - [self.renderingLayer renderDisplayLayer]; + [self.renderingLayer startRenderDisplayLayer]; if (!self.renderer) { return; @@ -258,6 +262,8 @@ static const float earth_gravity = 9.80665; [self handleMotion]; [self.renderer renderOnView:self]; + + [self.renderingLayer stopRenderDisplayLayer]; } - (BOOL)canRender { @@ -391,7 +397,7 @@ static const float earth_gravity = 9.80665; UITouch *touch = [tlist objectAtIndex:i]; int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); - DisplayServerIOS::get_singleton()->touches_cancelled(tid); + DisplayServerIOS::get_singleton()->touches_canceled(tid); } } [self clearTouches]; diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index 8d03e3d31c..3a245460b4 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -81,7 +81,13 @@ static void handle_crash(int sig) { print_error(vformat("Dumping the backtrace. %s", msg)); char **strings = backtrace_symbols(bt_buffer, size); // PIE executable relocation, zero for non-PIE executables +#ifdef __GLIBC__ + // This is a glibc only thing apparently. uintptr_t relocation = _r_debug.r_map->l_addr; +#else + // Non glibc systems apparently don't give PIE relocation info. + uintptr_t relocation = 0; +#endif //__GLIBC__ if (strings) { List<String> args; for (size_t i = 0; i < size; i++) { diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 747dcbd76c..7bed1a3447 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -271,7 +271,7 @@ def configure(env: "Environment"): env.Append(LIBS=["miniupnpc"]) # On Linux wchar_t should be 32-bits - # 16-bit library shouldn't be required due to compiler optimisations + # 16-bit library shouldn't be required due to compiler optimizations if not env["builtin_pcre2"]: env.ParseConfig("pkg-config libpcre2-32 --cflags --libs") @@ -338,12 +338,17 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/linuxbsd"]) + env.Append( + CPPDEFINES=[ + "LINUXBSD_ENABLED", + "UNIX_ENABLED", + ("_FILE_OFFSET_BITS", 64), + ] + ) + if env["x11"]: env.Append(CPPDEFINES=["X11_ENABLED"]) - env.Append(CPPDEFINES=["UNIX_ENABLED"]) - env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) - if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: @@ -400,9 +405,9 @@ def configure(env: "Environment"): # Link those statically for portability if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) - if env["use_llvm"]: + if env["use_llvm"] and platform.system() != "FreeBSD": env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a" else: - if env["use_llvm"]: + if env["use_llvm"] and platform.system() != "FreeBSD": env.Append(LIBS=["atomic"]) diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index a2c34bb874..d4f82cc81e 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1432,28 +1432,23 @@ void DisplayServerX11::_update_window_mouse_passthrough(WindowID p_window) { int event_base, error_base; const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base); if (ext_okay) { - Region region; if (windows[p_window].mpass) { - region = XCreateRegion(); + Region region = XCreateRegion(); + XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion(region); } else if (region_path.size() == 0) { - region = XCreateRegion(); - XRectangle rect; - rect.x = 0; - rect.y = 0; - rect.width = window_get_size_with_decorations(p_window).x; - rect.height = window_get_size_with_decorations(p_window).y; - XUnionRectWithRegion(&rect, region, region); + XShapeCombineMask(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, None, ShapeSet); } else { XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * region_path.size()); for (int i = 0; i < region_path.size(); i++) { points[i].x = region_path[i].x; points[i].y = region_path[i].y; } - region = XPolygonRegion(points, region_path.size(), EvenOddRule); + Region region = XPolygonRegion(points, region_path.size(), EvenOddRule); memfree(points); + XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion(region); } - XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet); - XDestroyRegion(region); } } @@ -4581,18 +4576,20 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W if (r_error != OK) { if (p_rendering_driver == "vulkan") { String executable_name = OS::get_singleton()->get_executable_path().get_file(); - OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" - "Please try updating your GPU driver or try using the OpenGL 3 driver.\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n'./" + - executable_name + " --rendering-driver opengl3'.\n " - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n'%s --rendering-driver opengl3'\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); } else { - OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n" - "Please try updating your GPU driver.\n" - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your video card drivers.\n\n" + "If you recently updated your video card drivers, try rebooting.", + "Unable to initialize OpenGL video driver"); } } return ds; diff --git a/platform/macos/detect.py b/platform/macos/detect.py index 67e4b49b14..cd46dab4f3 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -230,8 +230,7 @@ def configure(env: "Environment"): env.Append(LIBS=["pthread", "z"]) if env["opengl3"]: - env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"]) - env.Append(CCFLAGS=["-Wno-deprecated-declarations"]) # Disable deprecation warnings + env.Append(CPPDEFINES=["GLES3_ENABLED"]) env.Append(LINKFLAGS=["-framework", "OpenGL"]) env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"]) diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 63280c7887..fddd57aef2 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3142,7 +3142,9 @@ ObjectID DisplayServerMacOS::window_get_attached_instance_id(WindowID p_window) void DisplayServerMacOS::gl_window_make_current(DisplayServer::WindowID p_window_id) { #if defined(GLES3_ENABLED) - gl_manager->window_make_current(p_window_id); + if (gl_manager) { + gl_manager->window_make_current(p_window_id); + } #endif } @@ -3607,18 +3609,18 @@ DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, } else { executable_command = vformat("open %s --args --rendering-driver opengl3", OS::get_singleton()->get_bundle_resource_dir().path_join("../..").simplify_path()); } - OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" - "Please try updating your GPU driver or try using the OpenGL 3 driver.\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command: '" + - executable_command + "'.\n" - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your macOS version or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n'%s'", + executable_command), + "Unable to initialize Vulkan video driver"); } else { - OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n" - "Please try updating your GPU driver.\n" - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your macOS version.", + "Unable to initialize OpenGL video driver"); } } return ds; diff --git a/platform/macos/gl_manager_macos_legacy.h b/platform/macos/gl_manager_macos_legacy.h index 663bc5ea7b..c33b803d81 100644 --- a/platform/macos/gl_manager_macos_legacy.h +++ b/platform/macos/gl_manager_macos_legacy.h @@ -33,6 +33,9 @@ #if defined(MACOS_ENABLED) && defined(GLES3_ENABLED) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14 + #include "core/error/error_list.h" #include "core/os/os.h" #include "core/templates/local_vector.h" @@ -95,6 +98,8 @@ public: ~GLManager_MacOS(); }; +#pragma clang diagnostic push + #endif // MACOS_ENABLED && GLES3_ENABLED #endif // GL_MANAGER_MACOS_LEGACY_H diff --git a/platform/macos/gl_manager_macos_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm index a53b737289..65e978bfe6 100644 --- a/platform/macos/gl_manager_macos_legacy.mm +++ b/platform/macos/gl_manager_macos_legacy.mm @@ -33,6 +33,9 @@ #ifdef MACOS_ENABLED #ifdef GLES3_ENABLED +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14 + #include <stdio.h> #include <stdlib.h> @@ -232,5 +235,7 @@ GLManager_MacOS::~GLManager_MacOS() { release_current(); } +#pragma clang diagnostic pop + #endif // GLES3_ENABLED #endif // MACOS_ENABLED diff --git a/platform/macos/godot_content_view.h b/platform/macos/godot_content_view.h index ba7f15c32b..e660285e49 100644 --- a/platform/macos/godot_content_view.h +++ b/platform/macos/godot_content_view.h @@ -53,6 +53,9 @@ @end +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14 + @interface GodotContentView : RootView <NSTextInputClient> { DisplayServer::WindowID window_id; NSTrackingArea *tracking_area; @@ -73,4 +76,6 @@ @end +#pragma clang diagnostic pop + #endif // GODOT_CONTENT_VIEW_H diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm index 02cfca0841..ebfe8b1f6d 100644 --- a/platform/macos/godot_menu_delegate.mm +++ b/platform/macos/godot_menu_delegate.mm @@ -41,7 +41,7 @@ - (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action { NSString *ev_key = [[event charactersIgnoringModifiers] lowercaseString]; - NSUInteger ev_modifiers = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; + NSUInteger ev_modifiers = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; for (int i = 0; i < [menu numberOfItems]; i++) { const NSMenuItem *menu_item = [menu itemAtIndex:i]; if ([menu_item isEnabled] && [[menu_item keyEquivalent] compare:ev_key] == NSOrderedSame) { diff --git a/platform/macos/joypad_macos.cpp b/platform/macos/joypad_macos.cpp index b7b8e0604c..1fcd636a4b 100644 --- a/platform/macos/joypad_macos.cpp +++ b/platform/macos/joypad_macos.cpp @@ -316,7 +316,7 @@ bool JoypadMacOS::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { if (vendor && product_id) { char uid[128]; - sprintf(uid, "%08x%08x%08x%08x", OSSwapHostToBigInt32(3), OSSwapHostToBigInt32(vendor), OSSwapHostToBigInt32(product_id), OSSwapHostToBigInt32(version)); + snprintf(uid, 128, "%08x%08x%08x%08x", OSSwapHostToBigInt32(3), OSSwapHostToBigInt32(vendor), OSSwapHostToBigInt32(product_id), OSSwapHostToBigInt32(version)); input->joy_connection_changed(id, true, name, uid); } else { // Bluetooth device. diff --git a/platform/web/api/web_tools_editor_plugin.cpp b/platform/web/api/web_tools_editor_plugin.cpp index 7df9555b50..146a48db81 100644 --- a/platform/web/api/web_tools_editor_plugin.cpp +++ b/platform/web/api/web_tools_editor_plugin.cpp @@ -57,7 +57,7 @@ WebToolsEditorPlugin::WebToolsEditorPlugin() { add_tool_menu_item("Download Project Source", callable_mp(this, &WebToolsEditorPlugin::_download_zip)); } -void WebToolsEditorPlugin::_download_zip(Variant p_v) { +void WebToolsEditorPlugin::_download_zip() { if (!Engine::get_singleton() || !Engine::get_singleton()->is_editor_hint()) { ERR_PRINT("Downloading the project as a ZIP archive is only available in Editor mode."); return; diff --git a/platform/web/api/web_tools_editor_plugin.h b/platform/web/api/web_tools_editor_plugin.h index 72f4950b36..fc74899a58 100644 --- a/platform/web/api/web_tools_editor_plugin.h +++ b/platform/web/api/web_tools_editor_plugin.h @@ -41,7 +41,7 @@ class WebToolsEditorPlugin : public EditorPlugin { private: void _zip_file(String p_path, String p_base_path, zipFile p_zip); void _zip_recursive(String p_path, String p_base_path, zipFile p_zip); - void _download_zip(Variant p_v); + void _download_zip(); public: static void initialize(); diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 7dd0515d3f..fdb9d107a7 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -787,8 +787,10 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode RasterizerGLES3::make_current(); } else { - OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.", - "Unable to initialize video driver"); + OS::get_singleton()->alert( + "Your browser seems not to support WebGL 2.\n\n" + "If possible, consider updating your browser version and video card drivers.", + "Unable to initialize WebGL 2 video driver"); RasterizerDummy::make_current(); } #else diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp index e12f62f4ad..964bce01da 100644 --- a/platform/web/os_web.cpp +++ b/platform/web/os_web.cpp @@ -30,6 +30,7 @@ #include "os_web.h" +#include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" @@ -157,7 +158,22 @@ void OS_Web::vibrate_handheld(int p_duration_ms) { } String OS_Web::get_user_data_dir() const { - return "/userfs"; + String userfs = "/userfs"; + String appname = get_safe_dir_name(GLOBAL_GET("application/config/name")); + if (!appname.is_empty()) { + bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir"); + if (use_custom_dir) { + String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true); + if (custom_dir.is_empty()) { + custom_dir = appname; + } + return userfs.path_join(custom_dir).replace("\\", "/"); + } else { + return userfs.path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/"); + } + } + + return userfs.path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]"); } String OS_Web::get_cache_path() const { diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 914cd07b50..9a732c489d 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -741,6 +741,17 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod if (p_flags & WINDOW_FLAG_POPUP_BIT) { wd.is_popup = true; } + if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) { + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + + wd.layered_window = true; + } // Inherit icons from MAIN_WINDOW for all sub windows. HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0); @@ -778,6 +789,9 @@ void DisplayServerWindows::show_window(WindowID p_id) { SetForegroundWindow(wd.hWnd); // Slightly higher priority. SetFocus(wd.hWnd); // Set keyboard focus. } + if (wd.always_on_top) { + SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0)); + } } void DisplayServerWindows::delete_sub_window(WindowID p_window) { @@ -3499,6 +3513,7 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM alt_mem = false; control_mem = false; shift_mem = false; + gr_mem = false; // Restore mouse mode. _set_mouse_mode_impl(mouse_mode); @@ -4145,18 +4160,20 @@ DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_drive if (r_error != OK) { if (p_rendering_driver == "vulkan") { String executable_name = OS::get_singleton()->get_executable_path().get_file(); - OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" - "Please try updating your GPU driver or try using the OpenGL 3 driver.\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n'./" + - executable_name + " --rendering-driver opengl3'.\n " - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n'%s --rendering-driver opengl3'\n\n" + "If you have recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); } else { - OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n" - "Please try updating your GPU driver.\n" - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your video card drivers.\n\n" + "If you have recently updated your video card drivers, try rebooting.", + "Unable to initialize OpenGL video driver"); } } return ds; diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index 183958cf40..7ae26e6cf4 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -101,10 +101,12 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) { static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XSWirelessGamepad = { MAKELONG(0x045E, 0x0B13), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; if (memcmp(p_guid, &IID_ValveStreamingGamepad, sizeof(*p_guid)) == 0 || memcmp(p_guid, &IID_X360WiredGamepad, sizeof(*p_guid)) == 0 || - memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0) + memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0 || + memcmp(p_guid, &IID_XSWirelessGamepad, sizeof(*p_guid)) == 0) return true; PRAWINPUTDEVICELIST dev_list = nullptr; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index b3831573cf..08299d9b98 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -210,6 +210,8 @@ void OS_Windows::initialize() { } else if (!dwrite2_init) { print_verbose("Unable to load IDWriteFactory2, automatic system font fallback is disabled."); } + + FileAccessWindows::initialize(); } void OS_Windows::delete_main_loop() { @@ -252,6 +254,8 @@ void OS_Windows::finalize() { } void OS_Windows::finalize_core() { + FileAccessWindows::finalize(); + timeEndPeriod(1); memdelete(process_map); @@ -1166,8 +1170,17 @@ String OS_Windows::get_environment(const String &p_var) const { return ""; } -bool OS_Windows::set_environment(const String &p_var, const String &p_value) const { - return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data())); +void OS_Windows::set_environment(const String &p_var, const String &p_value) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + Char16String var = p_var.utf16(); + Char16String value = p_value.utf16(); + ERR_FAIL_COND_MSG(var.length() + value.length() + 2 > 32767, vformat("Invalid definition for environment variable '%s', cannot exceed 32767 characters.", p_var)); + SetEnvironmentVariableW((LPCWSTR)(var.get_data()), (LPCWSTR)(value.get_data())); +} + +void OS_Windows::unset_environment(const String &p_var) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete. } String OS_Windows::get_stdin_string() { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index c33e0f6740..05110c2614 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -186,7 +186,8 @@ public: virtual bool has_environment(const String &p_var) const override; virtual String get_environment(const String &p_var) const override; - virtual bool set_environment(const String &p_var, const String &p_value) const override; + virtual void set_environment(const String &p_var, const String &p_value) const override; + virtual void unset_environment(const String &p_var) const override; virtual Vector<String> get_system_fonts() const override; virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 5eb76bdbb5..f80da6e9ab 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -175,6 +175,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i return; //does not exist because it was likely removed from the tree } + lock_callback(); locked = true; if (body_in) { @@ -224,6 +225,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i } locked = false; + unlock_callback(); } void Area2D::_area_enter_tree(ObjectID p_id) { @@ -268,6 +270,8 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i if (!area_in && !E) { return; //likely removed from the tree } + + lock_callback(); locked = true; if (area_in) { @@ -317,6 +321,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i } locked = false; + unlock_callback(); } void Area2D::_clear_monitoring() { diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index c4de3a124b..7b681eac7a 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -391,10 +391,8 @@ bool AudioStreamPlayer2D::get_stream_paused() const { } Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() { - if (!stream_playbacks.is_empty()) { - return stream_playbacks[stream_playbacks.size() - 1]; - } - return nullptr; + ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback()."); + return stream_playbacks[stream_playbacks.size() - 1]; } void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) { diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index b2fee6ad82..caea753d99 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -94,10 +94,14 @@ void CollisionObject2D::_notification(int p_what) { bool disabled = !is_enabled(); if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { - if (area) { - PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); + if (callback_lock > 0) { + ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead."); } else { - PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + if (area) { + PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + } } } @@ -225,10 +229,14 @@ void CollisionObject2D::_apply_disabled() { switch (disable_mode) { case DISABLE_MODE_REMOVE: { if (is_inside_tree()) { - if (area) { - PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); + if (callback_lock > 0) { + ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead."); } else { - PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + if (area) { + PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + } } } } break; diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index d44e402e96..88429b145d 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -53,6 +53,7 @@ private: bool area = false; RID rid; + uint32_t callback_lock = 0; bool pickable = false; DisableMode disable_mode = DISABLE_MODE_REMOVE; @@ -83,6 +84,12 @@ private: void _apply_enabled(); protected: + _FORCE_INLINE_ void lock_callback() { callback_lock++; } + _FORCE_INLINE_ void unlock_callback() { + ERR_FAIL_COND(callback_lock == 0); + callback_lock--; + } + CollisionObject2D(RID p_rid, bool p_area); void _notification(int p_what); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 9fee99c6a7..1721bcde3b 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -434,6 +434,8 @@ struct _RigidBody2DInOut { }; void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { + lock_callback(); + set_block_transform_notify(true); // don't want notify (would feedback loop) if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) { set_global_transform(p_state->get_transform()); @@ -527,6 +529,8 @@ void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { contact_monitor->locked = false; } + + unlock_callback(); } void RigidBody2D::_apply_body_mode() { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index ed07d5d11e..8c5aab4c80 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -482,7 +482,11 @@ void TileMap::set_selected_layer(int p_layer_id) { ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size()); selected_layer = p_layer_id; emit_signal(SNAME("changed")); - _make_all_quadrants_dirty(); + + // Update the layers modulation. + for (unsigned int layer = 0; layer < layers.size(); layer++) { + _rendering_update_layer(layer); + } } int TileMap::get_selected_layer() const { @@ -653,8 +657,7 @@ void TileMap::set_layer_modulate(int p_layer, Color p_modulate) { } ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].modulate = p_modulate; - _clear_layer_internals(p_layer); - _recreate_layer_internals(p_layer); + _rendering_update_layer(p_layer); emit_signal(SNAME("changed")); } @@ -703,8 +706,7 @@ void TileMap::set_layer_z_index(int p_layer, int p_z_index) { } ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].z_index = p_z_index; - _clear_layer_internals(p_layer); - _recreate_layer_internals(p_layer); + _rendering_update_layer(p_layer); emit_signal(SNAME("changed")); update_configuration_warnings(); @@ -801,10 +803,10 @@ void TileMap::_make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator void TileMap::_make_all_quadrants_dirty() { // Make all quandrants dirty, then trigger an update later. - for (unsigned int layer = 0; layer < layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) { if (!E.value.dirty_list_element.in_list()) { - layers[layer].dirty_quadrant_list.add(&E.value.dirty_list_element); + layer.dirty_quadrant_list.add(&E.value.dirty_list_element); } } } @@ -1012,8 +1014,8 @@ void TileMap::_rendering_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_CANVAS: { bool node_visible = is_visible_in_tree(); - for (int layer = 0; layer < (int)layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) { TileMapQuadrant &q = E_quadrant.value; for (const KeyValue<Vector2i, RID> &kv : q.occluders) { Transform2D xform; @@ -1028,8 +1030,8 @@ void TileMap::_rendering_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { bool node_visible = is_visible_in_tree(); - for (int layer = 0; layer < (int)layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) { TileMapQuadrant &q = E_quadrant.value; // Update occluders transform. @@ -1048,8 +1050,8 @@ void TileMap::_rendering_notification(int p_what) { if (!is_inside_tree()) { return; } - for (int layer = 0; layer < (int)layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) { TileMapQuadrant &q = E_quadrant.value; // Update occluders transform. @@ -1069,8 +1071,8 @@ void TileMap::_rendering_notification(int p_what) { } break; case NOTIFICATION_EXIT_CANVAS: { - for (int layer = 0; layer < (int)layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) { TileMapQuadrant &q = E_quadrant.value; for (const KeyValue<Vector2i, RID> &kv : q.occluders) { RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, RID()); @@ -1103,6 +1105,19 @@ void TileMap::_rendering_update_layer(int p_layer) { rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree())); rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree())); rs->canvas_item_set_light_mask(ci, get_light_mask()); + + Color layer_modulate = get_layer_modulate(p_layer); + if (selected_layer >= 0 && p_layer != selected_layer) { + int z1 = get_layer_z_index(p_layer); + int z2 = get_layer_z_index(selected_layer); + if (z1 < z2 || (z1 == z2 && p_layer < selected_layer)) { + layer_modulate = layer_modulate.darkened(0.5); + } else if (z1 > z2 || (z1 == z2 && p_layer > selected_layer)) { + layer_modulate = layer_modulate.darkened(0.5); + layer_modulate.a *= 0.3; + } + } + rs->canvas_item_set_modulate(ci, layer_modulate); } void TileMap::_rendering_cleanup_layer(int p_layer) { @@ -1145,19 +1160,6 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List int prev_z_index = 0; RID prev_ci; - Color tile_modulate = get_self_modulate(); - tile_modulate *= get_layer_modulate(q.layer); - if (selected_layer >= 0) { - int z1 = get_layer_z_index(q.layer); - int z2 = get_layer_z_index(selected_layer); - if (z1 < z2 || (z1 == z2 && q.layer < selected_layer)) { - tile_modulate = tile_modulate.darkened(0.5); - } else if (z1 > z2 || (z1 == z2 && q.layer > selected_layer)) { - tile_modulate = tile_modulate.darkened(0.5); - tile_modulate.a *= 0.3; - } - } - // Iterate over the cells of the quadrant. for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) { TileMapCell c = get_cell(q.layer, E_cell.value, true); @@ -1227,7 +1229,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List } // Drawing the tile in the canvas item. - draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, tile_modulate, tile_data); + draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, get_self_modulate(), tile_data); // --- Occluders --- for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) { @@ -1255,16 +1257,16 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List if (_rendering_quadrant_order_dirty) { int index = -(int64_t)0x80000000; //always must be drawn below children. - for (int layer = 0; layer < (int)layers.size(); layer++) { + for (TileMapLayer &layer : layers) { // Sort the quadrants coords per local coordinates. RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> local_to_map; - for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) { + for (const KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) { local_to_map[map_to_local(E.key)] = E.key; } // Sort the quadrants. for (const KeyValue<Vector2i, Vector2i> &E : local_to_map) { - TileMapQuadrant &q = layers[layer].quadrant_map[E.value]; + TileMapQuadrant &q = layer.quadrant_map[E.value]; for (const RID &ci : q.canvas_items) { RS::get_singleton()->canvas_item_set_draw_index(ci, index++); } @@ -1451,8 +1453,8 @@ void TileMap::_physics_notification(int p_what) { if (is_inside_tree() && (!collision_animatable || in_editor)) { // Update the new transform directly if we are not in animatable mode. Transform2D gl_transform = get_global_transform(); - for (int layer = 0; layer < (int)layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) { TileMapQuadrant &q = E.value; for (RID body : q.bodies) { @@ -1474,8 +1476,8 @@ void TileMap::_physics_notification(int p_what) { if (is_inside_tree() && !in_editor && collision_animatable) { // Only active when animatable. Send the new transform to the physics... new_transform = get_global_transform(); - for (int layer = 0; layer < (int)layers.size(); layer++) { - for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) { + for (TileMapLayer &layer : layers) { + for (KeyValue<Vector2i, TileMapQuadrant> &E : layer.quadrant_map) { TileMapQuadrant &q = E.value; for (RID body : q.bodies) { @@ -1665,13 +1667,12 @@ void TileMap::_navigation_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSFORM_CHANGED: { if (is_inside_tree()) { - for (int layer = 0; layer < (int)layers.size(); layer++) { + for (TileMapLayer &layer : layers) { Transform2D tilemap_xform = get_global_transform(); - for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { + for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layer.quadrant_map) { TileMapQuadrant &q = E_quadrant.value; for (const KeyValue<Vector2i, Vector<RID>> &E_region : q.navigation_regions) { - for (int layer_index = 0; layer_index < E_region.value.size(); layer_index++) { - RID region = E_region.value[layer_index]; + for (const RID ®ion : E_region.value) { if (!region.is_valid()) { continue; } @@ -2071,7 +2072,7 @@ void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) { int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE); - // Get a cell source id from position + // Get a cell source id from position. const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map; HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords); @@ -2127,7 +2128,9 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies); - ERR_FAIL_COND_V_MSG(source_id == TileSet::INVALID_SOURCE, nullptr, vformat("Invalid TileSetSource at cell %s. Make sure a tile exists at this cell.", p_coords)); + if (source_id == TileSet::INVALID_SOURCE) { + return nullptr; + } Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); if (source.is_valid()) { @@ -2565,7 +2568,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay } } } - ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighbouring tile of %s", p_path[i + 1], p_path[i])); + ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_path[i + 1], p_path[i])); neighbor_list.push_back(found_bit); } @@ -2811,8 +2814,8 @@ void TileMap::clear_layer(int p_layer) { void TileMap::clear() { // Remove all tiles. _clear_internals(); - for (unsigned int i = 0; i < layers.size(); i++) { - layers[i].tile_map.clear(); + for (TileMapLayer &layer : layers) { + layer.tile_map.clear(); } _recreate_internals(); used_rect_cache_dirty = true; @@ -2839,7 +2842,7 @@ void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) { const int *r = p_data.ptr(); int offset = (format >= FORMAT_2) ? 3 : 2; - ERR_FAIL_COND_MSG(c % offset != 0, "Corrupted tile data."); + ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset)); clear_layer(p_layer); @@ -2979,11 +2982,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r #ifdef TOOLS_ENABLED Rect2 TileMap::_edit_get_rect() const { // Return the visible rect of the tilemap - if (pending_update) { - const_cast<TileMap *>(this)->_update_dirty_quadrants(); - } else { - const_cast<TileMap *>(this)->_recompute_rect_cache(); - } + const_cast<TileMap *>(this)->_recompute_rect_cache(); return rect_cache; } #endif @@ -3221,7 +3220,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const { ret = ret.floor(); } - // Compute the tile offset, and if we might the output for a neighbour top tile + // Compute the tile offset, and if we might the output for a neighbor top tile Vector2 in_tile_pos = raw_pos - ret; bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0; bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0; @@ -3285,7 +3284,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const { ret = ret.floor(); } - // Compute the tile offset, and if we might the output for a neighbour top tile + // Compute the tile offset, and if we might the output for a neighbor top tile Vector2 in_tile_pos = raw_pos - ret; bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0; bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0; @@ -3738,6 +3737,22 @@ TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const { return a; } +TypedArray<Vector2i> TileMap::get_used_cells_by_id(int p_layer, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const { + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TypedArray<Vector2i>()); + + // Returns the cells used in the tilemap. + TypedArray<Vector2i> a; + for (const KeyValue<Vector2i, TileMapCell> &E : layers[p_layer].tile_map) { + if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == E.value.source_id) && + (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == E.value.get_atlas_coords()) && + (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == E.value.alternative_tile)) { + a.push_back(E.key); + } + } + + return a; +} + Rect2i TileMap::get_used_rect() { // Not const because of cache // Return the rect of the currently used area if (used_rect_cache_dirty) { @@ -3940,15 +3955,15 @@ PackedStringArray TileMap::get_configuration_warnings() const { // Retrieve the set of Z index values with a Y-sorted layer. RBSet<int> y_sorted_z_index; - for (int layer = 0; layer < (int)layers.size(); layer++) { - if (layers[layer].y_sort_enabled) { - y_sorted_z_index.insert(layers[layer].z_index); + for (const TileMapLayer &layer : layers) { + if (layer.y_sort_enabled) { + y_sorted_z_index.insert(layer.z_index); } } // Check if we have a non-sorted layer in a Z-index with a Y-sorted layer. - for (int layer = 0; layer < (int)layers.size(); layer++) { - if (!layers[layer].y_sort_enabled && y_sorted_z_index.has(layers[layer].z_index)) { + for (const TileMapLayer &layer : layers) { + if (!layer.y_sort_enabled && y_sorted_z_index.has(layer.z_index)) { warnings.push_back(RTR("A Y-sorted layer has the same Z-index value as a not Y-sorted layer.\nThis may lead to unwanted behaviors, as a layer that is not Y-sorted will be Y-sorted as a whole with tiles from Y-sorted layers.")); break; } @@ -3957,8 +3972,8 @@ PackedStringArray TileMap::get_configuration_warnings() const { if (tile_set.is_valid() && tile_set->get_tile_shape() == TileSet::TILE_SHAPE_ISOMETRIC) { bool warn = !is_y_sort_enabled(); if (!warn) { - for (int layer = 0; layer < (int)layers.size(); layer++) { - if (!layers[layer].y_sort_enabled) { + for (const TileMapLayer &layer : layers) { + if (!layer.y_sort_enabled) { warn = true; break; } @@ -4030,6 +4045,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_surrounding_cells", "coords"), &TileMap::get_surrounding_cells); ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells); + ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "layer", "source_id", "atlas_coords", "alternative_tile"), &TileMap::get_used_cells_by_id, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect); ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index d187a917b5..7cf2a2eded 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -179,7 +179,7 @@ private: FORMAT_2, FORMAT_3 }; - mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present; + mutable DataFormat format = FORMAT_3; static constexpr float FP_ADJUST = 0.00001; @@ -340,7 +340,7 @@ public: VisibilityMode get_navigation_visibility_mode(); // Cells accessors. - void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); + void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); void erase_cell(int p_layer, const Vector2i &p_coords); int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; @@ -377,6 +377,7 @@ public: Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; TypedArray<Vector2i> get_used_cells(int p_layer) const; + TypedArray<Vector2i> get_used_cells_by_id(int p_layer, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const; Rect2i get_used_rect(); // Not const because of cache // Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index fa61ce5546..72f186c676 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -230,6 +230,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i return; //likely removed from the tree } + lock_callback(); locked = true; if (body_in) { @@ -279,6 +280,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i } locked = false; + unlock_callback(); } void Area3D::_clear_monitoring() { @@ -417,6 +419,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i return; //likely removed from the tree } + lock_callback(); locked = true; if (area_in) { @@ -466,6 +469,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i } locked = false; + unlock_callback(); } bool Area3D::is_monitoring() const { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 574f5363d4..7ed18d2d41 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -784,10 +784,8 @@ bool AudioStreamPlayer3D::get_stream_paused() const { } Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() { - if (!stream_playbacks.is_empty()) { - return stream_playbacks[stream_playbacks.size() - 1]; - } - return nullptr; + ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback()."); + return stream_playbacks[stream_playbacks.size() - 1]; } void AudioStreamPlayer3D::set_max_polyphony(int p_max_polyphony) { @@ -841,7 +839,7 @@ void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer3D::_set_playing); ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer3D::_is_active); - ClassDB::bind_method(D_METHOD("set_max_distance", "metres"), &AudioStreamPlayer3D::set_max_distance); + ClassDB::bind_method(D_METHOD("set_max_distance", "meters"), &AudioStreamPlayer3D::set_max_distance); ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer3D::get_max_distance); ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer3D::set_area_mask); diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index c408b0714a..19d1b83cab 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -43,6 +43,11 @@ void CollisionObject3D::_notification(int p_what) { } _update_debug_shapes(); } +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); // Used for warnings and only in editor. + } +#endif } break; case NOTIFICATION_EXIT_TREE: { @@ -78,6 +83,14 @@ void CollisionObject3D::_notification(int p_what) { _update_pickable(); } break; +#ifdef TOOLS_ENABLED + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; +#endif + case NOTIFICATION_TRANSFORM_CHANGED: { if (only_update_transform_changes) { return; @@ -100,10 +113,14 @@ void CollisionObject3D::_notification(int p_what) { bool disabled = !is_enabled(); if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + if (callback_lock > 0) { + ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead."); } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } } } @@ -223,10 +240,14 @@ void CollisionObject3D::_apply_disabled() { switch (disable_mode) { case DISABLE_MODE_REMOVE: { if (is_inside_tree()) { - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + if (callback_lock > 0) { + ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead."); } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } } } } break; @@ -716,6 +737,11 @@ PackedStringArray CollisionObject3D::get_configuration_warnings() const { warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.")); } + Vector3 scale = get_transform().get_basis().get_scale(); + if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { + warnings.push_back(RTR("With a non-uniform scale this node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size in children collision shapes instead.")); + } + return warnings; } diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 656b8c9bf1..ebcbb39e0d 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -52,6 +52,7 @@ private: bool area = false; RID rid; + uint32_t callback_lock = 0; DisableMode disable_mode = DISABLE_MODE_REMOVE; @@ -97,6 +98,12 @@ private: protected: CollisionObject3D(RID p_rid, bool p_area); + _FORCE_INLINE_ void lock_callback() { callback_lock++; } + _FORCE_INLINE_ void unlock_callback() { + ERR_FAIL_COND(callback_lock == 0); + callback_lock--; + } + void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index 5fb8970085..53a61c1368 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -104,6 +104,11 @@ void CollisionPolygon3D::_notification(int p_what) { if (parent) { _update_in_shape_owner(true); } +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } +#endif } break; case NOTIFICATION_UNPARENTED: { @@ -171,13 +176,18 @@ PackedStringArray CollisionPolygon3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape.")); + warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node.\nPlease only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape.")); } if (polygon.is_empty()) { warnings.push_back(RTR("An empty CollisionPolygon3D has no effect on collision.")); } + Vector3 scale = get_transform().get_basis().get_scale(); + if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { + warnings.push_back(RTR("A non-uniformly scaled CollisionPolygon3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change its polygon's vertices instead.")); + } + return warnings; } diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 1709a17bce..dbd50cfd19 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -99,6 +99,11 @@ void CollisionShape3D::_notification(int p_what) { if (parent) { _update_in_shape_owner(true); } +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } +#endif } break; case NOTIFICATION_UNPARENTED: { @@ -134,6 +139,11 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const { } } + Vector3 scale = get_transform().get_basis().get_scale(); + if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { + warnings.push_back(RTR("A non-uniformly scaled CollisionShape3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size of its shape resource instead.")); + } + return warnings; } diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index e9cc4e9479..fbcb1c8f2c 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -156,6 +156,10 @@ void Decal::_validate_property(PropertyInfo &p_property) const { if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } + + if (p_property.name == "sorting_offset") { + p_property.usage = PROPERTY_USAGE_DEFAULT; + } } PackedStringArray Decal::get_configuration_warnings() const { diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index f8c54809da..d0f71768d2 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -442,7 +442,7 @@ void Label3D::_shape() { TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i))); } - TypedArray<Vector2i> stt; + TypedArray<Vector3i> stt; if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) { GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt); } else { diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h index 8fc772e4b0..96cc941209 100644 --- a/scene/3d/label_3d.h +++ b/scene/3d/label_3d.h @@ -143,7 +143,7 @@ private: void _generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, const Color &p_modulate, int p_priority = 0, int p_outline_size = 0); protected: - GDVIRTUAL2RC(Array, _structured_text_parser, Array, String) + GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String) void _notification(int p_what); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index a6d63619df..fb74cffc94 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -455,8 +455,8 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc Plane best_plane; float best_plane_score = -1.0; - for (uint32_t i = 0; i < p_simplex_indices.size(); i++) { - const BSPSimplex &s = p_simplices[p_simplex_indices[i]]; + for (const int idx : p_simplex_indices) { + const BSPSimplex &s = p_simplices[idx]; for (int j = 0; j < 4; j++) { uint32_t plane_index = s.planes[j]; if (planes_tested[plane_index] == node_index) { @@ -484,8 +484,8 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc int over_count = 0; int under_count = 0; - for (uint32_t k = 0; k < p_simplex_indices.size(); k++) { - int side = _bsp_get_simplex_side(p_points, p_simplices, plane, p_simplex_indices[k]); + for (const int &index : p_simplex_indices) { + int side = _bsp_get_simplex_side(p_points, p_simplices, plane, index); if (side == -2) { continue; //this simplex is invalid, skip for now } else if (side < 0) { @@ -523,8 +523,7 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc LocalVector<int32_t> indices_under; //split again, but add to list - for (uint32_t i = 0; i < p_simplex_indices.size(); i++) { - uint32_t index = p_simplex_indices[i]; + for (const uint32_t index : p_simplex_indices) { int side = _bsp_get_simplex_side(p_points, p_simplices, best_plane, index); if (side == -2) { @@ -763,7 +762,15 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa MeshesFound &mf = meshes_found.write[m_i]; - Size2i lightmap_size = mf.mesh->get_lightmap_size_hint() * mf.lightmap_scale; + Size2i lightmap_size = mf.mesh->get_lightmap_size_hint(); + + if (lightmap_size == Size2i(0, 0)) { + // TODO we should compute a size if no lightmap hint is set, as we did in 3.x. + // For now set to basic size to avoid crash. + lightmap_size = Size2i(64, 64); + } + + lightmap_size *= mf.lightmap_scale; TypedArray<RID> overrides; overrides.resize(mf.overrides.size()); for (int i = 0; i < mf.overrides.size(); i++) { @@ -969,8 +976,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } } - for (uint32_t i = 0; i < new_probe_positions.size(); i++) { - probes_found.push_back(new_probe_positions[i]); + for (const Vector3 &position : new_probe_positions) { + probes_found.push_back(position); } } @@ -1211,8 +1218,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa LocalVector<BSPNode> bsp_nodes; LocalVector<int32_t> planes_tested; planes_tested.resize(bsp_planes.size()); - for (uint32_t i = 0; i < planes_tested.size(); i++) { - planes_tested[i] = 0x7FFFFFFF; + for (int &index : planes_tested) { + index = 0x7FFFFFFF; } if (p_bake_step) { @@ -1538,6 +1545,8 @@ void LightmapGI::_bind_methods() { BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_32); BIND_ENUM_CONSTANT(BAKE_ERROR_OK); + BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SCENE_ROOT); + BIND_ENUM_CONSTANT(BAKE_ERROR_FOREIGN_DATA); BIND_ENUM_CONSTANT(BAKE_ERROR_NO_LIGHTMAPPER); BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH); BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 1294571cc0..40ff9e4cad 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -124,6 +124,8 @@ public: enum BakeError { BAKE_ERROR_OK, + BAKE_ERROR_NO_SCENE_ROOT, + BAKE_ERROR_FOREIGN_DATA, BAKE_ERROR_NO_LIGHTMAPPER, BAKE_ERROR_NO_SAVE_PATH, BAKE_ERROR_NO_MESHES, diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 46956b0a2e..f4ab09cd9b 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -484,6 +484,8 @@ struct _RigidBodyInOut { }; void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { + lock_callback(); + set_ignore_transform_notification(true); set_global_transform(p_state->get_transform()); @@ -578,6 +580,8 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { contact_monitor->locked = false; } + + unlock_callback(); } void RigidBody3D::_notification(int p_what) { @@ -973,12 +977,11 @@ TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const { } PackedStringArray RigidBody3D::get_configuration_warnings() const { - Transform3D t = get_transform(); - - PackedStringArray warnings = Node::get_configuration_warnings(); + PackedStringArray warnings = CollisionObject3D::get_configuration_warnings(); - if (ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05) { - warnings.push_back(RTR("Size changes to RigidBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + Vector3 scale = get_transform().get_basis().get_scale(); + if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) { + warnings.push_back(RTR("Scale changes to RigidBody3D will be overridden by the physics engine when running.\nPlease change the size in children collision shapes instead.")); } return warnings; @@ -1343,7 +1346,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo motion = motion.slide(up_direction); result.travel = Vector3(); } else { - // Travel is too high to be safely cancelled, we take it into account. + // Travel is too high to be safely canceled, we take it into account. result.travel = result.travel.slide(up_direction); motion = motion.normalized() * result.travel.length(); } @@ -1351,7 +1354,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations. _snap_on_floor(true, false); } else { - // If the movement is not cancelled we only keep the remaining. + // If the movement is not canceled we only keep the remaining. motion = result.remainder; } diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index e8b51ceb92..e7e3084037 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -302,14 +302,6 @@ void SoftBody3D::_notification(int p_what) { _prepare_physics_server(); } } break; - -#ifdef TOOLS_ENABLED - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - } - } break; -#endif } } @@ -391,11 +383,6 @@ PackedStringArray SoftBody3D::get_configuration_warnings() const { warnings.push_back(RTR("This body will be ignored until you set a mesh.")); } - Transform3D t = get_transform(); - if ((ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05)) { - warnings.push_back(RTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); - } - return warnings; } diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 64fb0a7657..8026b12c2b 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -120,6 +120,12 @@ bool VisualInstance3D::is_sorting_use_aabb_center() const { return sorting_use_aabb_center; } +void VisualInstance3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + void VisualInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base); ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base); @@ -437,6 +443,12 @@ PackedStringArray GeometryInstance3D::get_configuration_warnings() const { return warnings; } +void GeometryInstance3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") { + p_property.usage = PROPERTY_USAGE_DEFAULT; + } +} + void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override); ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 190ed17753..ef0f7966e2 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -47,6 +47,7 @@ protected: void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL0RC(AABB, _get_aabb) public: @@ -140,6 +141,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 1ef0774828..a00b1d8ee1 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -229,15 +229,17 @@ AnimationNodeSync::AnimationNodeSync() { //////////////////////////////////////////////////////// void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const { - r_list->push_back(PropertyInfo(Variant::BOOL, active)); - r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); + r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort")); r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const { - if (p_parameter == active || p_parameter == prev_active) { + if (p_parameter == request) { + return ONE_SHOT_REQUEST_NONE; + } else if (p_parameter == active) { return false; } else if (p_parameter == time_to_restart) { return -1; @@ -246,6 +248,13 @@ Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_pa } } +bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const { + if (p_parameter == active) { + return true; + } + return false; +} + void AnimationNodeOneShot::set_fadein_time(double p_time) { fade_in = p_time; } @@ -303,41 +312,42 @@ bool AnimationNodeOneShot::has_filter() const { } double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) { + OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request)); bool cur_active = get_parameter(active); - bool cur_prev_active = get_parameter(prev_active); double cur_time = get_parameter(time); double cur_remaining = get_parameter(remaining); double cur_time_to_restart = get_parameter(time_to_restart); - if (!cur_active) { - //make it as if this node doesn't exist, pass input 0 by. - if (cur_prev_active) { - set_parameter(prev_active, false); - } + set_parameter(request, ONE_SHOT_REQUEST_NONE); + + bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE; + if (cur_request == ONE_SHOT_REQUEST_ABORT) { + set_parameter(active, false); + set_parameter(time_to_restart, -1); + return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); + } else if (!do_start && !cur_active) { if (cur_time_to_restart >= 0.0 && !p_seek) { cur_time_to_restart -= p_time; if (cur_time_to_restart < 0) { - //restart - set_parameter(active, true); - cur_active = true; + do_start = true; // Restart. } set_parameter(time_to_restart, cur_time_to_restart); } - - return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); + if (!do_start) { + return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync); + } } bool os_seek = p_seek; - if (p_seek) { cur_time = p_time; } - bool do_start = !cur_prev_active; if (do_start) { cur_time = 0; os_seek = true; - set_parameter(prev_active, true); + set_parameter(request, ONE_SHOT_REQUEST_NONE); + set_parameter(active, true); } real_t blend; @@ -375,7 +385,6 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter cur_remaining = os_rem; if (cur_remaining <= 0) { set_parameter(active, false); - set_parameter(prev_active, false); if (autorestart) { double restart_sec = autorestart_delay + Math::randd() * autorestart_random_delay; set_parameter(time_to_restart, restart_sec); @@ -419,6 +428,10 @@ void AnimationNodeOneShot::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay"); + BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_NONE); + BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_FIRE); + BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_ABORT); + BIND_ENUM_CONSTANT(MIX_MODE_BLEND); BIND_ENUM_CONSTANT(MIX_MODE_ADD); } @@ -640,9 +653,10 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con anims += inputs[i].name; } - r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims)); - r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); - r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::STRING, current_state, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); // For interface. + r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately. + r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally. + r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } @@ -650,13 +664,22 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const { if (p_parameter == time || p_parameter == prev_xfading) { return 0.0; - } else if (p_parameter == prev || p_parameter == prev_current) { + } else if (p_parameter == prev_index) { return -1; + } else if (p_parameter == transition_request || p_parameter == current_state) { + return String(); } else { return 0; } } +bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const { + if (p_parameter == current_state || p_parameter == current_index) { + return true; + } + return false; +} + String AnimationNodeTransition::get_caption() const { return "Transition"; } @@ -702,6 +725,17 @@ String AnimationNodeTransition::get_input_caption(int p_input) const { return inputs[p_input].name; } +int AnimationNodeTransition::find_input_caption(const String &p_name) const { + int idx = -1; + for (int i = 0; i < MAX_INPUTS; i++) { + if (inputs[i].name == p_name) { + idx = i; + break; + } + } + return idx; +} + void AnimationNodeTransition::set_xfade_time(double p_fade) { xfade_time = p_fade; } @@ -718,35 +752,62 @@ Ref<Curve> AnimationNodeTransition::get_xfade_curve() const { return xfade_curve; } -void AnimationNodeTransition::set_from_start(bool p_from_start) { - from_start = p_from_start; +void AnimationNodeTransition::set_reset(bool p_reset) { + reset = p_reset; } -bool AnimationNodeTransition::is_from_start() const { - return from_start; +bool AnimationNodeTransition::is_reset() const { + return reset; } double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) { - int cur_current = get_parameter(current); - int cur_prev = get_parameter(prev); - int cur_prev_current = get_parameter(prev_current); + String cur_transition_request = get_parameter(transition_request); + int cur_current_index = get_parameter(current_index); + int cur_prev_index = get_parameter(prev_index); double cur_time = get_parameter(time); double cur_prev_xfading = get_parameter(prev_xfading); - bool switched = cur_current != cur_prev_current; + bool switched = false; + bool restart = false; + + if (!cur_transition_request.is_empty()) { + int new_idx = find_input_caption(cur_transition_request); + if (new_idx >= 0) { + if (cur_current_index == new_idx) { + // Transition to same state. + restart = reset; + cur_prev_xfading = 0; + set_parameter(prev_xfading, 0); + cur_prev_index = -1; + set_parameter(prev_index, -1); + } else { + switched = true; + cur_prev_index = cur_current_index; + set_parameter(prev_index, cur_current_index); + } + cur_current_index = new_idx; + set_parameter(current_index, cur_current_index); + set_parameter(current_state, cur_transition_request); + } else { + ERR_PRINT("No such input: '" + cur_transition_request + "'"); + } + cur_transition_request = String(); + set_parameter(transition_request, cur_transition_request); + } - if (switched) { - set_parameter(prev_current, cur_current); - set_parameter(prev, cur_prev_current); + // Special case for restart. + if (restart) { + set_parameter(time, 0); + return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true); + } - cur_prev = cur_prev_current; + if (switched) { cur_prev_xfading = xfade_time; cur_time = 0; - switched = true; } - if (cur_current < 0 || cur_current >= enabled_inputs || cur_prev >= enabled_inputs) { + if (cur_current_index < 0 || cur_current_index >= enabled_inputs || cur_prev_index >= enabled_inputs) { return 0; } @@ -754,15 +815,15 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex if (sync) { for (int i = 0; i < enabled_inputs; i++) { - if (i != cur_current && i != cur_prev) { + if (i != cur_current_index && i != cur_prev_index) { blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true); } } } - if (cur_prev < 0) { // process current animation, check for transition + if (cur_prev_index < 0) { // process current animation, check for transition - rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); + rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); if (p_seek) { cur_time = p_time; @@ -770,8 +831,8 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex cur_time += p_time; } - if (inputs[cur_current].auto_advance && rem <= xfade_time) { - set_parameter(current, (cur_current + 1) % enabled_inputs); + if (inputs[cur_current_index].auto_advance && rem <= xfade_time) { + set_parameter(transition_request, get_input_caption((cur_current_index + 1) % enabled_inputs)); } } else { // cross-fading from prev to current @@ -783,21 +844,21 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex // Blend values must be more than CMP_EPSILON to process discrete keys in edge. real_t blend_inv = 1.0 - blend; - if (from_start && !p_seek && switched) { //just switched, seek to start of current - rem = blend_input(cur_current, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); + if (reset && !p_seek && switched) { //just switched, seek to start of current + rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); } else { - rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); + rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); } if (p_seek) { - blend_input(cur_prev, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true); + blend_input(cur_prev_index, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true); cur_time = p_time; } else { - blend_input(cur_prev, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true); + blend_input(cur_prev_index, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true); cur_time += p_time; cur_prev_xfading -= p_time; if (cur_prev_xfading < 0) { - set_parameter(prev, -1); + set_parameter(prev_index, -1); } } } @@ -829,6 +890,7 @@ void AnimationNodeTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption); ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption); + ClassDB::bind_method(D_METHOD("find_input_caption", "caption"), &AnimationNodeTransition::find_input_caption); ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time); ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time); @@ -836,13 +898,13 @@ void AnimationNodeTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve); ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve); - ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start); - ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start); + ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeTransition::set_reset); + ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeTransition::is_reset); - ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,31,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset"); for (int i = 0; i < MAX_INPUTS; i++) { ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i); diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index e72471202e..a1969bb621 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -96,6 +96,12 @@ class AnimationNodeOneShot : public AnimationNodeSync { GDCLASS(AnimationNodeOneShot, AnimationNodeSync); public: + enum OneShotRequest { + ONE_SHOT_REQUEST_NONE, + ONE_SHOT_REQUEST_FIRE, + ONE_SHOT_REQUEST_ABORT, + }; + enum MixMode { MIX_MODE_BLEND, MIX_MODE_ADD @@ -110,13 +116,8 @@ private: double autorestart_random_delay = 0.0; MixMode mix = MIX_MODE_BLEND; - /* bool active; - bool do_start; - double time; - double remaining;*/ - + StringName request = PNAME("request"); StringName active = PNAME("active"); - StringName prev_active = "prev_active"; StringName time = "time"; StringName remaining = "remaining"; StringName time_to_restart = "time_to_restart"; @@ -127,6 +128,7 @@ protected: public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; + virtual bool is_parameter_read_only(const StringName &p_parameter) const override; virtual String get_caption() const override; @@ -153,6 +155,7 @@ public: AnimationNodeOneShot(); }; +VARIANT_ENUM_CAST(AnimationNodeOneShot::OneShotRequest) VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode) class AnimationNodeAdd2 : public AnimationNodeSync { @@ -284,22 +287,19 @@ class AnimationNodeTransition : public AnimationNodeSync { InputData inputs[MAX_INPUTS]; int enabled_inputs = 0; - /* - double prev_xfading; - int prev; - double time; - int current; - int prev_current; */ - - StringName prev_xfading = "prev_xfading"; - StringName prev = "prev"; StringName time = "time"; - StringName current = PNAME("current"); - StringName prev_current = "prev_current"; + StringName prev_xfading = "prev_xfading"; + StringName prev_index = "prev_index"; + StringName current_index = PNAME("current_index"); + StringName current_state = PNAME("current_state"); + StringName transition_request = PNAME("transition_request"); + + StringName prev_frame_current = "pf_current"; + StringName prev_frame_current_idx = "pf_current_idx"; double xfade_time = 0.0; Ref<Curve> xfade_curve; - bool from_start = true; + bool reset = true; void _update_inputs(); @@ -310,6 +310,7 @@ protected: public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; + virtual bool is_parameter_read_only(const StringName &p_parameter) const override; virtual String get_caption() const override; @@ -321,6 +322,7 @@ public: void set_input_caption(int p_input, const String &p_name); String get_input_caption(int p_input) const; + int find_input_caption(const String &p_name) const; void set_xfade_time(double p_fade); double get_xfade_time() const; @@ -328,8 +330,8 @@ public: void set_xfade_curve(const Ref<Curve> &p_curve); Ref<Curve> get_xfade_curve() const; - void set_from_start(bool p_from_start); - bool is_from_start() const; + void set_reset(bool p_reset); + bool is_reset() const; double process(double p_time, bool p_seek, bool p_is_external_seeking) override; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index f5df64dbdd..02f1e9f9a6 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -107,6 +107,15 @@ Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const { return xfade_curve; } +void AnimationNodeStateMachineTransition::set_reset(bool p_reset) { + reset = p_reset; + emit_changed(); +} + +bool AnimationNodeStateMachineTransition::is_reset() const { + return reset; +} + void AnimationNodeStateMachineTransition::set_priority(int p_priority) { priority = p_priority; emit_changed(); @@ -132,6 +141,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve); ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve); + ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeStateMachineTransition::set_reset); + ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeStateMachineTransition::is_reset); + ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority); ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority); @@ -140,6 +152,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority"); ADD_GROUP("Switch", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode"); @@ -164,18 +179,27 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() { //////////////////////////////////////////////////////// -void AnimationNodeStateMachinePlayback::travel(const StringName &p_state) { - start_request_travel = true; - start_request = p_state; +void AnimationNodeStateMachinePlayback::travel(const StringName &p_state, bool p_reset_on_teleport) { + travel_request = p_state; + reset_request_on_teleport = p_reset_on_teleport; stop_request = false; } -void AnimationNodeStateMachinePlayback::start(const StringName &p_state) { - start_request_travel = false; +void AnimationNodeStateMachinePlayback::start(const StringName &p_state, bool p_reset) { + travel_request = StringName(); + reset_request = p_reset; + _start(p_state); +} + +void AnimationNodeStateMachinePlayback::_start(const StringName &p_state) { start_request = p_state; stop_request = false; } +void AnimationNodeStateMachinePlayback::next() { + next_request = true; +} + void AnimationNodeStateMachinePlayback::stop() { stop_request = true; } @@ -188,7 +212,7 @@ StringName AnimationNodeStateMachinePlayback::get_current_node() const { return current; } -StringName AnimationNodeStateMachinePlayback::get_blend_from_node() const { +StringName AnimationNodeStateMachinePlayback::get_fading_from_node() const { return fading_from; } @@ -212,7 +236,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta path.clear(); //a new one will be needed if (current == p_travel) { - return true; //nothing to do + return false; // Will teleport oneself (restart). } Vector2 current_pos = p_state_machine->states[current].position; @@ -323,6 +347,15 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta } double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) { + double rem = _process(p_state_machine, p_time, p_seek, p_is_external_seeking); + start_request = StringName(); + next_request = false; + stop_request = false; + reset_request_on_teleport = false; + return rem; +} + +double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) { if (p_time == -1) { Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node; if (anodesm.is_valid()) { @@ -335,14 +368,13 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s //if not playing and it can restart, then restart if (!playing && start_request == StringName()) { if (!stop_request && p_state_machine->start_node) { - start(p_state_machine->start_node); + _start(p_state_machine->start_node); } else { return 0; } } if (playing && stop_request) { - stop_request = false; playing = false; return 0; } @@ -350,42 +382,47 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s bool play_start = false; if (start_request != StringName()) { - if (start_request_travel) { - if (!playing) { - if (!stop_request && p_state_machine->start_node) { - // can restart, just postpone traveling - path.clear(); - current = p_state_machine->start_node; - playing = true; - play_start = true; - } else { - // stopped, invalid state - String node_name = start_request; - start_request = StringName(); //clear start request - ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?"); - } - } else { - if (!_travel(p_state_machine, start_request)) { - // can't travel, then teleport - path.clear(); - current = start_request; - play_start = true; - } - start_request = StringName(); //clear start request - } + // teleport to start + if (p_state_machine->states.has(start_request)) { + path.clear(); + current = start_request; + playing = true; + play_start = true; } else { - // teleport to start - if (p_state_machine->states.has(start_request)) { + StringName node = start_request; + ERR_FAIL_V_MSG(0, "No such node: '" + node + "'"); + } + } else if (travel_request != StringName()) { + if (!playing) { + if (!stop_request && p_state_machine->start_node) { + // can restart, just postpone traveling path.clear(); - current = start_request; + current = p_state_machine->start_node; playing = true; play_start = true; - start_request = StringName(); //clear start request } else { - StringName node = start_request; - start_request = StringName(); //clear start request - ERR_FAIL_V_MSG(0, "No such node: '" + node + "'"); + // stopped, invalid state + String node_name = travel_request; + travel_request = StringName(); + ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?"); } + } else { + if (!_travel(p_state_machine, travel_request)) { + // can't travel, then teleport + if (p_state_machine->states.has(travel_request)) { + path.clear(); + if (current != travel_request || reset_request_on_teleport) { + current = travel_request; + play_start = true; + reset_request = reset_request_on_teleport; + } + } else { + StringName node = travel_request; + travel_request = StringName(); + ERR_FAIL_V_MSG(0, "No such node: '" + node + "'"); + } + } + travel_request = StringName(); } } @@ -396,8 +433,11 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s current = p_state_machine->start_node; } - len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true); - pos_current = 0; + if (reset_request) { + len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true); + pos_current = 0; + reset_request = false; + } } if (!p_state_machine->states.has(current)) { @@ -421,7 +461,8 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s if (current_curve.is_valid()) { fade_blend = current_curve->sample(fade_blend); } - double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + + double rem = do_start ? len_current : p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. if (fading_from != StringName()) { double fade_blend_inv = 1.0 - fade_blend; @@ -457,6 +498,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s next_xfade = p_state_machine->transitions[i].transition->get_xfade_time(); current_curve = p_state_machine->transitions[i].transition->get_xfade_curve(); switch_mode = p_state_machine->transitions[i].transition->get_switch_mode(); + reset_request = p_state_machine->transitions[i].transition->is_reset(); next = path[0]; } } @@ -513,6 +555,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve(); next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time(); switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode(); + reset_request = p_state_machine->transitions[auto_advance_to].transition->is_reset(); } } @@ -567,7 +610,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s goto_next = fading_from == StringName(); } - if (goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped + if (next_request || goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped if (next_xfade) { //time to fade, baby fading_from = current; @@ -591,7 +634,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s current = next; - len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here. + if (reset_request) { + len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here. + } if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { pos_current = MIN(pos_current, len_current); p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true); @@ -652,13 +697,15 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima } void AnimationNodeStateMachinePlayback::_bind_methods() { - ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachinePlayback::travel); - ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachinePlayback::start); + ClassDB::bind_method(D_METHOD("travel", "to_node", "reset_on_teleport"), &AnimationNodeStateMachinePlayback::travel, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("start", "node", "reset"), &AnimationNodeStateMachinePlayback::start, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("next"), &AnimationNodeStateMachinePlayback::next); ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop); ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing); ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node); ClassDB::bind_method(D_METHOD("get_current_play_position"), &AnimationNodeStateMachinePlayback::get_current_play_pos); ClassDB::bind_method(D_METHOD("get_current_length"), &AnimationNodeStateMachinePlayback::get_current_length); + ClassDB::bind_method(D_METHOD("get_fading_from_node"), &AnimationNodeStateMachinePlayback::get_fading_from_node); ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::get_travel_path); } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index 116589eb2f..1b4e010a06 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -57,6 +57,7 @@ private: StringName advance_condition_name; float xfade_time = 0.0; Ref<Curve> xfade_curve; + bool reset = true; int priority = 1; String advance_expression; @@ -84,6 +85,9 @@ public: void set_xfade_time(float p_xfade); float get_xfade_time() const; + void set_reset(bool p_reset); + bool is_reset() const; + void set_xfade_curve(const Ref<Curve> &p_curve); Ref<Curve> get_xfade_curve() const; @@ -131,10 +135,15 @@ class AnimationNodeStateMachinePlayback : public Resource { bool playing = false; StringName start_request; - bool start_request_travel = false; + StringName travel_request; + bool reset_request = false; + bool reset_request_on_teleport = false; + bool next_request = false; bool stop_request = false; bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel); + void _start(const StringName &p_state); + double _process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking); double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking); @@ -144,12 +153,13 @@ protected: static void _bind_methods(); public: - void travel(const StringName &p_state); - void start(const StringName &p_state); + void travel(const StringName &p_state, bool p_reset_on_teleport = true); + void start(const StringName &p_state, bool p_reset = true); + void next(); void stop(); bool is_playing() const; StringName get_current_node() const; - StringName get_blend_from_node() const; + StringName get_fading_from_node() const; Vector<StringName> get_travel_path() const; float get_current_play_pos() const; float get_current_length() const; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 0771c7ef06..047997ca09 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -143,8 +143,8 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const { } else if (name.begins_with("libraries")) { Dictionary d; - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - d[animation_libraries[i].name] = animation_libraries[i].library; + for (const AnimationLibraryData &lib : animation_libraries) { + d[lib.name] = lib.library; } r_ret = d; @@ -1269,13 +1269,13 @@ void AnimationPlayer::_animation_set_cache_update() { bool clear_cache_needed = false; // Update changed and add otherwise - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { - StringName key = animation_libraries[i].name == StringName() ? K.key : StringName(String(animation_libraries[i].name) + "/" + String(K.key)); + for (const AnimationLibraryData &lib : animation_libraries) { + for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) { + StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key)); if (!animation_set.has(key)) { AnimationData ad; ad.animation = K.value; - ad.animation_library = animation_libraries[i].name; + ad.animation_library = lib.name; ad.name = key; ad.last_update = animation_set_update_pass; animation_set.insert(ad.name, ad); @@ -1283,11 +1283,11 @@ void AnimationPlayer::_animation_set_cache_update() { AnimationData &ad = animation_set[key]; if (ad.last_update != animation_set_update_pass) { // Was not updated, update. If the animation is duplicated, the second one will be ignored. - if (ad.animation != K.value || ad.animation_library != animation_libraries[i].name) { + if (ad.animation != K.value || ad.animation_library != lib.name) { // Animation changed, update and clear caches. clear_cache_needed = true; ad.animation = K.value; - ad.animation_library = animation_libraries[i].name; + ad.animation_library = lib.name; } ad.last_update = animation_set_update_pass; @@ -1405,11 +1405,11 @@ Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref int insert_pos = 0; - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - ERR_FAIL_COND_V_MSG(animation_libraries[i].name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name)); - ERR_FAIL_COND_V_MSG(animation_libraries[i].library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + animation_libraries[i].name.operator String() + "'."); + for (const AnimationLibraryData &lib : animation_libraries) { + ERR_FAIL_COND_V_MSG(lib.name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name)); + ERR_FAIL_COND_V_MSG(lib.library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + lib.name.operator String() + "'."); - if (animation_libraries[i].name.operator String() >= p_name.operator String()) { + if (lib.name.operator String() >= p_name.operator String()) { break; } @@ -1468,21 +1468,21 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S #endif bool found = false; - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - ERR_FAIL_COND_MSG(animation_libraries[i].name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name)); - if (animation_libraries[i].name == p_name) { + for (AnimationLibraryData &lib : animation_libraries) { + ERR_FAIL_COND_MSG(lib.name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name)); + if (lib.name == p_name) { found = true; - animation_libraries[i].name = p_new_name; + lib.name = p_new_name; // rename connections - animation_libraries[i].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added)); - animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed)); - animation_libraries[i].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed)); + lib.library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added)); + lib.library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed)); + lib.library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed)); - animation_libraries[i].library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name)); - animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name)); - animation_libraries[i].library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name)); + lib.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name)); + lib.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name)); + lib.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name)); - for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { + for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) { StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key)); StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key)); _rename_animation(old_name, new_name); @@ -1502,8 +1502,8 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S } bool AnimationPlayer::has_animation_library(const StringName &p_name) const { - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - if (animation_libraries[i].name == p_name) { + for (const AnimationLibraryData &lib : animation_libraries) { + if (lib.name == p_name) { return true; } } @@ -1512,9 +1512,9 @@ bool AnimationPlayer::has_animation_library(const StringName &p_name) const { } Ref<AnimationLibrary> AnimationPlayer::get_animation_library(const StringName &p_name) const { - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - if (animation_libraries[i].name == p_name) { - return animation_libraries[i].library; + for (const AnimationLibraryData &lib : animation_libraries) { + if (lib.name == p_name) { + return lib.library; } } ERR_FAIL_V(Ref<AnimationLibrary>()); @@ -1522,15 +1522,15 @@ Ref<AnimationLibrary> AnimationPlayer::get_animation_library(const StringName &p TypedArray<StringName> AnimationPlayer::_get_animation_library_list() const { TypedArray<StringName> ret; - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - ret.push_back(animation_libraries[i].name); + for (const AnimationLibraryData &lib : animation_libraries) { + ret.push_back(lib.name); } return ret; } void AnimationPlayer::get_animation_library_list(List<StringName> *p_libraries) const { - for (uint32_t i = 0; i < animation_libraries.size(); i++) { - p_libraries->push_back(animation_libraries[i].name); + for (const AnimationLibraryData &lib : animation_libraries) { + p_libraries->push_back(lib.name); } } @@ -1736,11 +1736,11 @@ String AnimationPlayer::get_assigned_animation() const { } void AnimationPlayer::pause() { - _stop_internal(false); + _stop_internal(false, false); } -void AnimationPlayer::stop() { - _stop_internal(true); +void AnimationPlayer::stop(bool p_keep_state) { + _stop_internal(true, p_keep_state); } void AnimationPlayer::set_speed_scale(float p_speed) { @@ -1960,14 +1960,18 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) { processing = p_process; } -void AnimationPlayer::_stop_internal(bool p_reset) { +void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) { _stop_playing_caches(p_reset); Playback &c = playback; c.blend.clear(); if (p_reset) { - is_stopping = true; - seek(0, true); - is_stopping = false; + if (p_keep_state) { + c.current.pos = 0; + } else { + is_stopping = true; + seek(0, true); + is_stopping = false; + } c.current.from = nullptr; c.current.speed_scale = 1; } @@ -2139,7 +2143,7 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("play", "name", "custom_blend", "custom_speed", "from_end"), &AnimationPlayer::play, DEFVAL(""), DEFVAL(-1), DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("play_backwards", "name", "custom_blend"), &AnimationPlayer::play_backwards, DEFVAL(""), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("pause"), &AnimationPlayer::pause); - ClassDB::bind_method(D_METHOD("stop"), &AnimationPlayer::stop); + ClassDB::bind_method(D_METHOD("stop", "keep_state"), &AnimationPlayer::stop, DEFVAL(false)); ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing); ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 8dfa7aed27..7e7d12f982 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -295,7 +295,7 @@ private: void _animation_changed(const StringName &p_name); void _set_process(bool p_process, bool p_force = false); - void _stop_internal(bool p_reset); + void _stop_internal(bool p_reset, bool p_keep_state); bool playing = false; @@ -349,7 +349,7 @@ public: Vector<String> get_queue(); void clear_queue(); void pause(); - void stop(); + void stop(bool p_keep_state = false); bool is_playing() const; String get_current_animation() const; void set_current_animation(const String &p_anim); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index ab341797c7..077a5696bb 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -54,13 +54,19 @@ Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter return ret; } +bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const { + bool ret = false; + GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret); + return ret; +} + void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND(!state); ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path)); ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name)); StringName path = state->tree->property_parent_map[base_path][p_name]; - state->tree->property_map[path] = p_value; + state->tree->property_map[path].first = p_value; } Variant AnimationNode::get_parameter(const StringName &p_name) const { @@ -69,7 +75,7 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const { ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name), Variant()); StringName path = state->tree->property_parent_map[base_path][p_name]; - return state->tree->property_map[path]; + return state->tree->property_map[path].first; } void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { @@ -427,6 +433,7 @@ void AnimationNode::_bind_methods() { GDVIRTUAL_BIND(_get_parameter_list); GDVIRTUAL_BIND(_get_child_by_name, "name"); GDVIRTUAL_BIND(_get_parameter_default_value, "parameter"); + GDVIRTUAL_BIND(_is_parameter_read_only, "parameter"); GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking"); GDVIRTUAL_BIND(_get_caption); GDVIRTUAL_BIND(_has_filter); @@ -747,7 +754,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { if (has_reset_anim) { int rt = reset_anim->find_track(path, track_type); if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { - track_bezier->init_value = reset_anim->track_get_key_value(rt, 0); + track_bezier->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0]; } } } break; @@ -1889,7 +1896,10 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A StringName key = pinfo.name; if (!property_map.has(p_base_path + key)) { - property_map[p_base_path + key] = node->get_parameter_default_value(key); + Pair<Variant, bool> param; + param.first = node->get_parameter_default_value(key); + param.second = node->is_parameter_read_only(key); + property_map[p_base_path + key] = param; } property_parent_map[p_base_path][key] = p_base_path + key; @@ -1931,7 +1941,10 @@ bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) { } if (property_map.has(p_name)) { - property_map[p_name] = p_value; + if (is_inside_tree() && property_map[p_name].second) { + return false; // Prevent to set property by user. + } + property_map[p_name].first = p_value; return true; } @@ -1944,7 +1957,7 @@ bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const { } if (property_map.has(p_name)) { - r_ret = property_map[p_name]; + r_ret = property_map[p_name].first; return true; } diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 2c1be6199c..52d3e1bd41 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -117,6 +117,7 @@ protected: GDVIRTUAL0RC(Array, _get_parameter_list) GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName) GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName) + GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName) GDVIRTUAL3RC(double, _process, double, bool, bool) GDVIRTUAL0RC(String, _get_caption) GDVIRTUAL0RC(bool, _has_filter) @@ -124,6 +125,7 @@ protected: public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const; virtual Variant get_parameter_default_value(const StringName &p_parameter) const; + virtual bool is_parameter_read_only(const StringName &p_parameter) const; void set_parameter(const StringName &p_name, const Variant &p_value); Variant get_parameter(const StringName &p_name) const; @@ -304,7 +306,7 @@ private: void _update_properties(); List<PropertyInfo> properties; HashMap<StringName, HashMap<StringName, StringName>> property_parent_map; - HashMap<StringName, Variant> property_map; + HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag. struct Activity { uint64_t last_pass = 0; diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 42f76068e7..d40fc10441 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -308,10 +308,8 @@ void AudioStreamPlayer::_bus_layout_changed() { } Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() { - if (!stream_playbacks.is_empty()) { - return stream_playbacks[stream_playbacks.size() - 1]; - } - return nullptr; + ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback()."); + return stream_playbacks[stream_playbacks.size() - 1]; } void AudioStreamPlayer::_bind_methods() { diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index d0326290ac..472299b135 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -385,6 +385,7 @@ void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) { if (shortcut_feedback) { if (shortcut_feedback_timer == nullptr) { shortcut_feedback_timer = memnew(Timer); + shortcut_feedback_timer->set_one_shot(true); add_child(shortcut_feedback_timer); shortcut_feedback_timer->set_wait_time(GLOBAL_GET("gui/timers/button_shortcut_feedback_highlight_time")); shortcut_feedback_timer->connect("timeout", callable_mp(this, &BaseButton::_shortcut_feedback_timeout)); diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 4356e91e41..c977d9d2fb 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -548,7 +548,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } if (k->is_action("ui_text_dedent", true)) { - do_unindent(); + unindent_lines(); accept_event(); return; } @@ -898,50 +898,6 @@ void CodeEdit::indent_lines() { end_complex_operation(); } -void CodeEdit::do_unindent() { - if (!is_editable()) { - return; - } - - int cc = get_caret_column(); - - if (has_selection() || cc <= 0) { - unindent_lines(); - return; - } - - begin_complex_operation(); - Vector<int> caret_edit_order = get_caret_index_edit_order(); - for (const int &c : caret_edit_order) { - int cl = get_caret_line(c); - const String &line = get_line(cl); - - if (line[cc - 1] == '\t') { - remove_text(cl, cc - 1, cl, cc); - set_caret_column(MAX(0, cc - 1), c == 0, c); - adjust_carets_after_edit(c, cl, cc, cl, cc - 1); - continue; - } - - if (line[cc - 1] != ' ') { - continue; - } - - int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); - if (spaces_to_remove > 0) { - for (int i = 1; i <= spaces_to_remove; i++) { - if (line[cc - i] != ' ') { - spaces_to_remove = i - 1; - break; - } - } - remove_text(cl, cc - spaces_to_remove, cl, cc); - set_caret_column(MAX(0, cc - spaces_to_remove), c == 0, c); - } - } - end_complex_operation(); -} - void CodeEdit::unindent_lines() { if (!is_editable()) { return; @@ -2204,7 +2160,6 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_auto_indent_prefixes"), &CodeEdit::get_auto_indent_prefixes); ClassDB::bind_method(D_METHOD("do_indent"), &CodeEdit::do_indent); - ClassDB::bind_method(D_METHOD("do_unindent"), &CodeEdit::do_unindent); ClassDB::bind_method(D_METHOD("indent_lines"), &CodeEdit::indent_lines); ClassDB::bind_method(D_METHOD("unindent_lines"), &CodeEdit::unindent_lines); diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index c050b2266f..55fc5aa2ae 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -289,7 +289,6 @@ public: TypedArray<String> get_auto_indent_prefixes() const; void do_indent(); - void do_unindent(); void indent_lines(); void unindent_lines(); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index b5846cb692..da29bc823f 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -35,11 +35,6 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "scene/gui/color_mode.h" - -#ifdef TOOLS_ENABLED -#include "editor/editor_settings.h" -#endif - #include "thirdparty/misc/ok_color.h" #include "thirdparty/misc/ok_color_shader.h" @@ -50,31 +45,6 @@ void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _update_color(); -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - if (preset_cache.is_empty()) { - PackedColorArray saved_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "presets", PackedColorArray()); - for (int i = 0; i < saved_presets.size(); i++) { - preset_cache.push_back(saved_presets[i]); - } - } - - for (int i = 0; i < preset_cache.size(); i++) { - presets.push_back(preset_cache[i]); - } - - if (recent_preset_cache.is_empty()) { - PackedColorArray saved_recent_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "recent_presets", PackedColorArray()); - for (int i = 0; i < saved_recent_presets.size(); i++) { - recent_preset_cache.push_back(saved_recent_presets[i]); - } - } - - for (int i = 0; i < recent_preset_cache.size(); i++) { - recent_presets.push_back(recent_preset_cache[i]); - } - } -#endif [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { @@ -404,6 +374,40 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) { } } +#ifdef TOOLS_ENABLED +void ColorPicker::set_editor_settings(Object *p_editor_settings) { + if (editor_settings) { + return; + } + editor_settings = p_editor_settings; + + if (preset_cache.is_empty()) { + PackedColorArray saved_presets = editor_settings->call(SNAME("get_project_metadata"), "color_picker", "presets", PackedColorArray()); + for (int i = 0; i < saved_presets.size(); i++) { + preset_cache.push_back(saved_presets[i]); + } + } + + for (int i = 0; i < preset_cache.size(); i++) { + presets.push_back(preset_cache[i]); + } + + if (recent_preset_cache.is_empty()) { + PackedColorArray saved_recent_presets = editor_settings->call(SNAME("get_project_metadata"), "color_picker", "recent_presets", PackedColorArray()); + for (int i = 0; i < saved_recent_presets.size(); i++) { + recent_preset_cache.push_back(saved_recent_presets[i]); + } + } + + for (int i = 0; i < recent_preset_cache.size(); i++) { + recent_presets.push_back(recent_preset_cache[i]); + } + + _update_presets(); + _update_recent_presets(); +} +#endif + HSlider *ColorPicker::get_slider(int p_idx) { if (p_idx < SLIDER_COUNT) { return sliders[p_idx]; @@ -471,7 +475,7 @@ ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const { void ColorPicker::_reset_theme() { Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat)); - style_box_flat->set_default_margin(SIDE_TOP, 16 * get_theme_default_base_scale()); + style_box_flat->set_content_margin(SIDE_TOP, 16 * get_theme_default_base_scale()); style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp()); for (int i = 0; i < SLIDER_COUNT; i++) { sliders[i]->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); @@ -553,7 +557,7 @@ void ColorPicker::_update_presets() { } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (editor_settings) { // Only load preset buttons when the only child is the add-preset button. if (preset_container->get_child_count() == 1) { for (int i = 0; i < preset_cache.size(); i++) { @@ -567,7 +571,7 @@ void ColorPicker::_update_presets() { void ColorPicker::_update_recent_presets() { #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (editor_settings) { int recent_preset_count = recent_preset_hbc->get_child_count(); for (int i = 0; i < recent_preset_count; i++) { memdelete(recent_preset_hbc->get_child(0)); @@ -642,7 +646,7 @@ inline int ColorPicker::_get_preset_size() { void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size)); btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1))); - btn_preset_new->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCDU(btn_preset_new, ColorPicker); btn_preset_new->set_button_group(preset_group); preset_container->add_child(btn_preset_new); btn_preset_new->set_pressed(true); @@ -743,9 +747,9 @@ void ColorPicker::add_preset(const Color &p_color) { } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (editor_settings) { PackedColorArray arr_to_save = get_presets(); - EditorSettings::get_singleton()->set_project_metadata("color_picker", "presets", arr_to_save); + editor_settings->call(SNAME("set_project_metadata"), "color_picker", "presets", arr_to_save); } #endif } @@ -764,9 +768,9 @@ void ColorPicker::add_recent_preset(const Color &p_color) { _select_from_preset_container(p_color); #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (editor_settings) { PackedColorArray arr_to_save = get_recent_presets(); - EditorSettings::get_singleton()->set_project_metadata("color_picker", "recent_presets", arr_to_save); + editor_settings->call(SNAME("set_project_metadata"), "color_picker", "recent_presets", arr_to_save); } #endif } @@ -787,9 +791,9 @@ void ColorPicker::erase_preset(const Color &p_color) { } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (editor_settings) { PackedColorArray arr_to_save = get_presets(); - EditorSettings::get_singleton()->set_project_metadata("color_picker", "presets", arr_to_save); + editor_settings->call(SNAME("set_project_metadata"), "color_picker", "presets", arr_to_save); } #endif } @@ -811,9 +815,9 @@ void ColorPicker::erase_recent_preset(const Color &p_color) { } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (editor_settings) { PackedColorArray arr_to_save = get_recent_presets(); - EditorSettings::get_singleton()->set_project_metadata("color_picker", "recent_presets", arr_to_save); + editor_settings->call(SNAME("set_project_metadata"), "color_picker", "recent_presets", arr_to_save); } #endif } @@ -890,7 +894,7 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) { alpha_slider->add_theme_style_override("slider", style_box_empty); } else { Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat)); - style_box_flat->set_default_margin(SIDE_TOP, 16 * get_theme_default_base_scale()); + style_box_flat->set_content_margin(SIDE_TOP, 16 * get_theme_default_base_scale()); style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp()); if (!slider_theme_modified) { @@ -1544,10 +1548,6 @@ void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_picker_shape", "shape"), &ColorPicker::set_picker_shape); ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ColorPicker::_get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ColorPicker::_can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ColorPicker::_drop_data_fw); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL"), "set_color_mode", "get_color_mode"); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 5eaeecca2a..f7578612cd 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -100,6 +100,10 @@ private: static List<Color> preset_cache; static List<Color> recent_preset_cache; +#ifdef TOOLS_ENABLED + Object *editor_settings = nullptr; +#endif + int current_slider_count = SLIDER_COUNT; static const int MODE_BUTTON_COUNT = 3; @@ -231,6 +235,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED + void set_editor_settings(Object *p_editor_settings); +#endif + HSlider *get_slider(int idx); Vector<float> get_active_slider_values(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 10dbad232a..fead0878fb 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1582,10 +1582,6 @@ void Control::set_block_minimum_size_adjust(bool p_block) { data.block_minimum_size_adjust = p_block; } -bool Control::is_minimum_size_adjust_blocked() const { - return data.block_minimum_size_adjust; -} - Size2 Control::get_minimum_size() const { Vector2 ms; GDVIRTUAL_CALL(_get_minimum_size, ms); @@ -1823,19 +1819,6 @@ bool Control::is_focus_owner_in_shortcut_context() const { // Drag and drop handling. -void Control::set_drag_forwarding_compat(Object *p_base) { - if (p_base != nullptr) { - data.forward_drag = Callable(p_base, "_get_drag_data_fw").bind(this); - data.forward_can_drop = Callable(p_base, "_can_drop_data_fw").bind(this); - data.forward_drop = Callable(p_base, "_drop_data_fw").bind(this); - - } else { - data.forward_drag = Callable(); - data.forward_can_drop = Callable(); - data.forward_drop = Callable(); - } -} - void Control::set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop) { data.forward_drag = p_drag; data.forward_can_drop = p_can_drop; @@ -2782,9 +2765,9 @@ void Control::end_bulk_theme_override() { // Internationalization. -TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { +TypedArray<Vector3i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) { - TypedArray<Vector2i> ret; + TypedArray<Vector3i> ret; GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret); return ret; } else { diff --git a/scene/gui/control.h b/scene/gui/control.h index 22a37dd89e..a93a88e5b4 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -145,7 +145,7 @@ public: TEXT_DIRECTION_AUTO = TextServer::DIRECTION_AUTO, TEXT_DIRECTION_LTR = TextServer::DIRECTION_LTR, TEXT_DIRECTION_RTL = TextServer::DIRECTION_RTL, - TEXT_DIRECTION_INHERITED, + TEXT_DIRECTION_INHERITED = TextServer::DIRECTION_INHERITED, }; private: @@ -330,7 +330,7 @@ protected: // Internationalization. - virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + virtual TypedArray<Vector3i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; // Base object overrides. @@ -340,7 +340,7 @@ protected: // Exposed virtual methods. GDVIRTUAL1RC(bool, _has_point, Vector2) - GDVIRTUAL2RC(TypedArray<Vector2i>, _structured_text_parser, Array, String) + GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String) GDVIRTUAL0RC(Vector2, _get_minimum_size) GDVIRTUAL1RC(Variant, _get_drag_data, Vector2) @@ -464,7 +464,6 @@ public: void update_minimum_size(); void set_block_minimum_size_adjust(bool p_block); - bool is_minimum_size_adjust_blocked() const; virtual Size2 get_minimum_size() const; virtual Size2 get_combined_minimum_size() const; @@ -503,7 +502,6 @@ public: // Drag and drop handling. virtual void set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop); - virtual void set_drag_forwarding_compat(Object *p_base); virtual Variant get_drag_data(const Point2 &p_point); virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const; virtual void drop_data(const Point2 &p_point, const Variant &p_data); @@ -634,4 +632,10 @@ VARIANT_ENUM_CAST(Control::LayoutMode); VARIANT_ENUM_CAST(Control::LayoutDirection); VARIANT_ENUM_CAST(Control::TextDirection); +// G = get_drag_data_fw, C = can_drop_data_fw, D = drop_data_fw, U = underscore +#define SET_DRAG_FORWARDING_CD(from, to) from->set_drag_forwarding(Callable(), callable_mp(this, &to::can_drop_data_fw).bind(from), callable_mp(this, &to::drop_data_fw).bind(from)); +#define SET_DRAG_FORWARDING_CDU(from, to) from->set_drag_forwarding(Callable(), callable_mp(this, &to::_can_drop_data_fw).bind(from), callable_mp(this, &to::_drop_data_fw).bind(from)); +#define SET_DRAG_FORWARDING_GCD(from, to) from->set_drag_forwarding(callable_mp(this, &to::get_drag_data_fw).bind(from), callable_mp(this, &to::can_drop_data_fw).bind(from), callable_mp(this, &to::drop_data_fw).bind(from)); +#define SET_DRAG_FORWARDING_GCDU(from, to) from->set_drag_forwarding(callable_mp(this, &to::_get_drag_data_fw).bind(from), callable_mp(this, &to::_can_drop_data_fw).bind(from), callable_mp(this, &to::_drop_data_fw).bind(from)); + #endif // CONTROL_H diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 4365db2ea2..dfe9ea3b08 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -136,7 +136,7 @@ void AcceptDialog::_cancel_pressed() { call_deferred(SNAME("hide")); - emit_signal(SNAME("cancelled")); + emit_signal(SNAME("canceled")); cancel_pressed(); @@ -372,7 +372,7 @@ void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_ok_button_text"), &AcceptDialog::get_ok_button_text); ADD_SIGNAL(MethodInfo("confirmed")); - ADD_SIGNAL(MethodInfo("cancelled")); + ADD_SIGNAL(MethodInfo("canceled")); ADD_SIGNAL(MethodInfo("custom_action", PropertyInfo(Variant::STRING_NAME, "action"))); ADD_PROPERTY(PropertyInfo(Variant::STRING, "ok_button_text"), "set_ok_button_text", "get_ok_button_text"); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 372baeadae..25a27d5e1a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -309,12 +309,6 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) { shape_changed = true; } -Ref<Texture2D> ItemList::get_item_tag_icon(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Texture2D>()); - - return items[p_idx].tag_icon; -} - void ItemList::set_item_selectable(int p_idx, bool p_selectable) { if (p_idx < 0) { p_idx += get_item_count(); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 848f9a2ba9..934318dbb4 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -191,7 +191,6 @@ public: Variant get_item_metadata(int p_idx) const; void set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon); - Ref<Texture2D> get_item_tag_icon(int p_idx) const; void set_item_tooltip_enabled(int p_idx, const bool p_enabled); bool is_item_tooltip_enabled(int p_idx) const; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index cafea83f16..f59702835c 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -222,6 +222,7 @@ void Label::_shape() { } } lines_dirty = false; + lines_shaped_last_width = get_size().width; } _update_visible(); @@ -596,7 +597,13 @@ void Label::_notification(int p_what) { } break; case NOTIFICATION_RESIZED: { - lines_dirty = true; + // It may happen that the reshaping due to this size change triggers a cascade of re-layout + // across the hierarchy where this label belongs to in a way that its size changes multiple + // times, but ending up with the original size it was already shaped for. + // This check prevents the catastrophic, freezing infinite cascade of re-layout. + if (lines_shaped_last_width != get_size().width) { + lines_dirty = true; + } } break; } } diff --git a/scene/gui/label.h b/scene/gui/label.h index 2350525236..b80646810b 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -49,6 +49,8 @@ private: bool uppercase = false; bool lines_dirty = true; + int lines_shaped_last_width = -1; + bool dirty = true; bool font_dirty = true; RID text_rid; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index e5bb64b225..ad4e667278 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2576,7 +2576,7 @@ LineEdit::LineEdit(const String &p_placeholder) { set_placeholder(p_placeholder); - set_editable(true); // Initialise to opposite first, so we get past the early-out in set_editable. + set_editable(true); // Initialize to opposite first, so we get past the early-out in set_editable. } LineEdit::~LineEdit() { diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 224e405d41..5b27983851 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -214,10 +214,10 @@ void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) { PopupMenu *pm = Object::cast_to<PopupMenu>(n); ERR_FAIL_COND_MSG(!pm, "Item subnode is not a PopupMenu: " + p_child->get_item_submenu(i) + "."); - DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, p_child->get_item_text(i), p_menu_name + "/" + itos(i)); + DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, atr(p_child->get_item_text(i)), p_menu_name + "/" + itos(i)); _update_submenu(p_menu_name + "/" + itos(i), pm); } else { - int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, p_child->get_item_text(i), callable_mp(p_child, &PopupMenu::activate_item), Callable(), i); + int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, atr(p_child->get_item_text(i)), callable_mp(p_child, &PopupMenu::activate_item), Callable(), i); if (p_child->is_item_checkable(i)) { DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true); @@ -290,7 +290,7 @@ void MenuBar::_update_menu() { if (menu_cache[i].hidden) { continue; } - String menu_name = String(popups[i]->get_meta("_menu_name", popups[i]->get_name())); + String menu_name = atr(String(popups[i]->get_meta("_menu_name", popups[i]->get_name()))); index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", menu_name, root_name + "/" + itos(i), index); if (menu_cache[i].disabled) { @@ -525,7 +525,7 @@ void MenuBar::shape(Menu &p_menu) { } else { p_menu.text_buf->set_direction((TextServer::Direction)text_direction); } - p_menu.text_buf->add_string(p_menu.name, theme_cache.font, theme_cache.font_size, language); + p_menu.text_buf->add_string(atr(p_menu.name), theme_cache.font, theme_cache.font_size, language); } void MenuBar::_refresh_menu_names() { diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index c939e7a48a..2ea1b93810 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -59,9 +59,9 @@ void Popup::_initialize_visible_parents() { void Popup::_deinitialize_visible_parents() { if (is_embedded()) { - for (uint32_t i = 0; i < visible_parents.size(); ++i) { - visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + for (Window *parent_window : visible_parents) { + parent_window->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + parent_window->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); } visible_parents.clear(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 4e8a44dd63..ddc11d97b9 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -594,17 +594,17 @@ void PopupMenu::_draw_items() { int content_left = content_center - content_size / 2; int content_right = content_center + content_size / 2; if (content_left > item_ofs.x) { - int sep_h = theme_cache.labeled_separator_left->get_center_size().height + theme_cache.labeled_separator_left->get_minimum_size().height; + int sep_h = theme_cache.labeled_separator_left->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); theme_cache.labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h))); } if (content_right < display_width) { - int sep_h = theme_cache.labeled_separator_right->get_center_size().height + theme_cache.labeled_separator_right->get_minimum_size().height; + int sep_h = theme_cache.labeled_separator_right->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); theme_cache.labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h))); } } else { - int sep_h = theme_cache.separator_style->get_center_size().height + theme_cache.separator_style->get_minimum_size().height; + int sep_h = theme_cache.separator_style->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); theme_cache.separator_style->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h))); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 5ab64b35fd..a7e50a765e 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -4074,8 +4074,8 @@ void RichTextLabel::append_text(const String &p_bbcode) { st_parser_type = TextServer::STRUCTURED_TEXT_EMAIL; } else if (subtag_a[1] == "l" || subtag_a[1] == "list") { st_parser_type = TextServer::STRUCTURED_TEXT_LIST; - } else if (subtag_a[1] == "n" || subtag_a[1] == "none") { - st_parser_type = TextServer::STRUCTURED_TEXT_NONE; + } else if (subtag_a[1] == "n" || subtag_a[1] == "gdscript") { + st_parser_type = TextServer::STRUCTURED_TEXT_GDSCRIPT; } else if (subtag_a[1] == "c" || subtag_a[1] == "custom") { st_parser_type = TextServer::STRUCTURED_TEXT_CUSTOM; } diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index e617b2ca77..b8faf22a59 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -433,7 +433,7 @@ void ScrollBar::_notification(int p_what) { double ScrollBar::get_grabber_min_size() const { Ref<StyleBox> grabber = theme_cache.grabber_style; - Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size(); + Size2 gminsize = grabber->get_minimum_size(); return (orientation == VERTICAL) ? gminsize.height : gminsize.width; } @@ -500,7 +500,7 @@ Size2 ScrollBar::get_minimum_size() const { Size2 minsize; if (orientation == VERTICAL) { - minsize.width = MAX(incr->get_size().width, (bg->get_minimum_size() + bg->get_center_size()).width); + minsize.width = MAX(incr->get_size().width, bg->get_minimum_size().width); minsize.height += incr->get_size().height; minsize.height += decr->get_size().height; minsize.height += bg->get_minimum_size().height; @@ -508,7 +508,7 @@ Size2 ScrollBar::get_minimum_size() const { } if (orientation == HORIZONTAL) { - minsize.height = MAX(incr->get_size().height, (bg->get_center_size() + bg->get_minimum_size()).height); + minsize.height = MAX(incr->get_size().height, bg->get_minimum_size().height); minsize.width += incr->get_size().width; minsize.width += decr->get_size().width; minsize.width += bg->get_minimum_size().width; diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp index 45185de698..b0879c1931 100644 --- a/scene/gui/separator.cpp +++ b/scene/gui/separator.cpp @@ -51,7 +51,7 @@ void Separator::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { Size2i size = get_size(); - Size2i ssize = theme_cache.separator_style->get_minimum_size() + theme_cache.separator_style->get_center_size(); + Size2i ssize = theme_cache.separator_style->get_minimum_size(); if (orientation == VERTICAL) { theme_cache.separator_style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y)); diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 040559dab8..292a4cfea2 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -33,7 +33,7 @@ #include "core/os/keyboard.h" Size2 Slider::get_minimum_size() const { - Size2i ss = theme_cache.slider_style->get_minimum_size() + theme_cache.slider_style->get_center_size(); + Size2i ss = theme_cache.slider_style->get_minimum_size(); Size2i rs = theme_cache.grabber_icon->get_size(); if (orientation == HORIZONTAL) { @@ -212,7 +212,7 @@ void Slider::_notification(int p_what) { } if (orientation == VERTICAL) { - int widget_width = style->get_minimum_size().width + style->get_center_size().width; + int widget_width = style->get_minimum_size().width; double areasize = size.height - grabber->get_size().height; style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height))); grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().height / 2))); @@ -229,7 +229,7 @@ void Slider::_notification(int p_what) { } grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2 + get_theme_constant(SNAME("grabber_offset")), size.height - ratio * areasize - grabber->get_size().height)); } else { - int widget_height = style->get_minimum_size().height + style->get_center_size().height; + int widget_height = style->get_minimum_size().height; double areasize = size.width - grabber->get_size().width; style->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(size.width, widget_height))); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 3457cfa94f..208cb29772 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -954,9 +954,6 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); - ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &TabContainer::_get_drag_data_fw); - ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TabContainer::_can_drop_data_fw); - ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TabContainer::_drop_data_fw); ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab"))); @@ -975,7 +972,7 @@ void TabContainer::_bind_methods() { TabContainer::TabContainer() { tab_bar = memnew(TabBar); - tab_bar->set_drag_forwarding_compat(this); + SET_DRAG_FORWARDING_GCDU(tab_bar, TabContainer); add_child(tab_bar, false, INTERNAL_MODE_FRONT); tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE); tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed)); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 108a533a74..8ffaa9e81f 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1208,7 +1208,15 @@ void TextEdit::_notification(int p_what) { char_ofs = 0; } for (int j = 0; j < gl_size; j++) { - const Variant *color_data = color_map.getptr(glyphs[j].start); + int64_t color_start = -1; + for (const Variant *key = color_map.next(nullptr); key; key = color_map.next(key)) { + if (int64_t(*key) <= glyphs[j].start) { + color_start = *key; + } else { + break; + } + } + const Variant *color_data = (color_start >= 0) ? color_map.getptr(color_start) : nullptr; if (color_data != nullptr) { current_color = (color_data->operator Dictionary()).get("color", font_color); if (!editable && current_color.a > font_readonly_color.a) { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 426acc4996..2ec2f39409 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -274,7 +274,7 @@ private: void _update_placeholder(); - /* Initialise to opposite first, so we get past the early-out in set_editable. */ + /* Initialize to opposite first, so we get past the early-out in set_editable. */ bool editable = false; TextDirection text_direction = TEXT_DIRECTION_AUTO; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 2138f10ad0..2d985c2324 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -332,7 +332,7 @@ void TreeItem::set_structured_text_bidi_override(int p_column, TextServer::Struc } TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_column) const { - ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_NONE); + ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_DEFAULT); return cells[p_column].st_parser; } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 9be1a6431b..7b0554442c 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -388,6 +388,16 @@ Color CanvasItem::get_modulate() const { return modulate; } +Color CanvasItem::get_modulate_in_tree() const { + Color final_modulate = modulate; + CanvasItem *parent_item = get_parent_item(); + while (parent_item) { + final_modulate *= parent_item->get_modulate(); + parent_item = parent_item->get_parent_item(); + } + return final_modulate; +} + void CanvasItem::set_as_top_level(bool p_top_level) { if (top_level == p_top_level) { return; @@ -531,10 +541,13 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) { Vector<Point2> points; points.resize(p_point_count); - const real_t delta_angle = p_end_angle - p_start_angle; + Point2 *points_ptr = points.ptrw(); + + // Clamp angle difference to full circle so arc won't overlap itself. + const real_t delta_angle = CLAMP(p_end_angle - p_start_angle, -Math_TAU, Math_TAU); for (int i = 0; i < p_point_count; i++) { real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle; - points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius); + points_ptr[i] = p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius; } draw_polyline(points, p_color, p_width, p_antialiased); @@ -557,44 +570,47 @@ void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vec void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + Rect2 rect = p_rect.abs(); + if (p_filled) { if (p_width != -1.0) { WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\"."); } - RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, rect, p_color); + } else if (p_width >= rect.size.width || p_width >= rect.size.height) { + RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, rect.grow(0.5f * p_width), p_color); } else { // Thick lines are offset depending on their width to avoid partial overlapping. - // Thin lines don't require an offset, so don't apply one in this case - real_t offset; - if (p_width >= 0) { - offset = p_width / 2.0; - } else { - offset = 0.0; - } + // Thin lines are drawn without offset. The result may not be perfect. + real_t offset = (p_width >= 0) ? 0.5f * p_width : 0.0f; + // Top line. RenderingServer::get_singleton()->canvas_item_add_line( canvas_item, - p_rect.position + Size2(-offset, 0), - p_rect.position + Size2(p_rect.size.width + offset, 0), + rect.position + Size2(-offset, 0), + rect.position + Size2(-offset + rect.size.width, 0), p_color, p_width); + // Right line. RenderingServer::get_singleton()->canvas_item_add_line( canvas_item, - p_rect.position + Size2(p_rect.size.width, offset), - p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset), + rect.position + Size2(rect.size.width, -offset), + rect.position + Size2(rect.size.width, -offset + rect.size.height), p_color, p_width); + // Bottom line. RenderingServer::get_singleton()->canvas_item_add_line( canvas_item, - p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height), - p_rect.position + Size2(-offset, p_rect.size.height), + rect.position + Size2(offset + rect.size.width, rect.size.height), + rect.position + Size2(offset, rect.size.height), p_color, p_width); + // Left line. RenderingServer::get_singleton()->canvas_item_add_line( canvas_item, - p_rect.position + Size2(0, p_rect.size.height - offset), - p_rect.position + Size2(0, offset), + rect.position + Size2(0, offset + rect.size.height), + rect.position + Size2(0, offset), p_color, p_width); } @@ -970,9 +986,9 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(-1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(-1.0), DEFVAL(2.0), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(-1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(-1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(-1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(-1.0)); ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(-1.0)); ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(-1.0)); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index b2c12b2ea2..644fe856ec 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -224,6 +224,7 @@ public: void set_modulate(const Color &p_modulate); Color get_modulate() const; + Color get_modulate_in_tree() const; void set_self_modulate(const Color &p_self_modulate); Color get_self_modulate() const; @@ -249,9 +250,9 @@ public: void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, real_t p_dash = 2.0, bool p_aligned = true); void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false); - void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); - void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false); - void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); + void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false); + void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = -1.0, bool p_antialiased = false); + void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false); void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = -1.0); void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = -1.0); void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = -1.0); diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp index e36cbc4414..c54e61580f 100644 --- a/scene/main/multiplayer_api.cpp +++ b/scene/main/multiplayer_api.cpp @@ -135,7 +135,7 @@ Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint return err; } if (r_buffer) { - // The first byte is not used by the marshalling, so store the type + // The first byte is not used by the marshaling, so store the type // so we know how to decompress and decode this variant. r_buffer[0] = p_variant.get_type(); } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 0e4abf7421..0b1f8f101c 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -279,7 +279,10 @@ void Node::_propagate_exit_tree() { //block while removing children #ifdef DEBUG_ENABLED - SceneDebugger::remove_from_cache(data.scene_file_path, this); + if (!data.scene_file_path.is_empty()) { + // Only remove if file path is set (optimization). + SceneDebugger::remove_from_cache(data.scene_file_path, this); + } #endif data.blocked++; @@ -305,7 +308,6 @@ void Node::_propagate_exit_tree() { } // exit groups - for (KeyValue<StringName, GroupData> &E : data.grouped) { data.tree->remove_from_group(E.key, this); E.value.group = nullptr; @@ -1166,7 +1168,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) { void Node::remove_child(Node *p_child) { ERR_FAIL_NULL(p_child); - ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `remove_child()` failed. Consider using `remove_child.call_deferred(child)` instead."); + ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy adding/removing children, `remove_child()` can't be called at this time. Consider using `remove_child.call_deferred(child)` instead."); int child_count = data.children.size(); Node **children = data.children.ptrw(); @@ -1197,11 +1199,13 @@ void Node::remove_child(Node *p_child) { data.internal_children_back--; } + data.blocked++; p_child->_set_tree(nullptr); //} remove_child_notify(p_child); p_child->notification(NOTIFICATION_UNPARENTED); + data.blocked--; data.children.remove_at(idx); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 9c7e04c433..07bcf45899 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1402,7 +1402,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) { xform = sw->get_canvas_transform(); } - Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform); + Control *ret = _gui_find_control_at_pos(sw, p_global, xform); if (ret) { return ret; } @@ -1411,7 +1411,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) { return nullptr; } -Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) { +Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform) { if (!p_node->is_visible()) { return nullptr; // Canvas item hidden, discard. } @@ -1431,7 +1431,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ continue; } - Control *ret = _gui_find_control_at_pos(ci, p_global, matrix, r_inv_xform); + Control *ret = _gui_find_control_at_pos(ci, p_global, matrix); if (ret) { return ret; } @@ -1449,7 +1449,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ Control *drag_preview = _gui_get_drag_preview(); if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) { - r_inv_xform = matrix; return c; } @@ -1496,12 +1495,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Point2 mpos = mb->get_position(); if (mb->is_pressed()) { - Size2 pos = mpos; if (!gui.mouse_focus_mask.is_empty()) { // Do not steal mouse focus and stuff while a focus mask exists. gui.mouse_focus_mask.set_flag(mouse_button_to_mask(mb->get_button_index())); } else { - gui.mouse_focus = gui_find_control(pos); + gui.mouse_focus = gui_find_control(mpos); gui.last_mouse_focus = gui.mouse_focus; if (!gui.mouse_focus) { @@ -1520,10 +1518,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { mb = mb->xformed_by(Transform2D()); // Make a copy of the event. - mb->set_global_position(pos); - - pos = gui.focus_inv_xform.xform(pos); - + Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos); mb->set_position(pos); #ifdef DEBUG_ENABLED @@ -1587,11 +1582,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { return; } - Size2 pos = mpos; - mb = mb->xformed_by(Transform2D()); // Make a copy. - mb->set_global_position(pos); - pos = gui.focus_inv_xform.xform(pos); + Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos); mb->set_position(pos); Control *mouse_focus = gui.mouse_focus; @@ -1894,11 +1886,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool stopped = false; if (over->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); // Make a copy. - if (over == gui.mouse_focus) { - pos = gui.focus_inv_xform.xform(pos); - } else { - pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); - } + pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); touch_event->set_position(pos); stopped = _gui_call_input(over, touch_event); } @@ -1913,11 +1901,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = control_id.is_valid() ? Object::cast_to<Control>(ObjectDB::get_instance(control_id)) : nullptr; if (over && over->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); // Make a copy. - if (over == gui.last_mouse_focus) { - pos = gui.focus_inv_xform.xform(pos); - } else { - pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); - } + pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); touch_event->set_position(pos); stopped = _gui_call_input(over, touch_event); @@ -1943,11 +1927,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool stopped = false; if (over->can_process()) { gesture_event = gesture_event->xformed_by(Transform2D()); // Make a copy. - if (over == gui.mouse_focus) { - pos = gui.focus_inv_xform.xform(pos); - } else { - pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); - } + pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); gesture_event->set_position(pos); stopped = _gui_call_input(over, gesture_event); } @@ -2394,7 +2374,6 @@ void Viewport::_post_gui_grab_click_focus() { } gui.mouse_focus = focus_grabber; - gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse(); click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos); for (int i = 0; i < 3; i++) { @@ -3937,7 +3916,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mesh_lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_mesh_lod_threshold", "get_mesh_lod_threshold"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Lighting,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); #ifndef _3D_DISABLED ADD_GROUP("Scaling 3D", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode"); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 9f182682d7..603e92b071 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -374,7 +374,6 @@ private: ObjectID drag_preview_id; Ref<SceneTreeTimer> tooltip_timer; double tooltip_delay = 0.0; - Transform2D focus_inv_xform; bool roots_order_dirty = false; List<Control *> roots; int canvas_sort_index = 0; //for sorting items with canvas as root @@ -403,7 +402,7 @@ private: void _gui_call_notification(Control *p_control, int p_what); void _gui_sort_roots(); - Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform); + Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform); void _gui_input_event(Ref<InputEvent> p_event); void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2()); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 4baedc8c14..2c6599d849 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -227,7 +227,7 @@ void Window::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NONE; } - if (p_property.name == "current_screen" && initial_position != WINDOW_INITIAL_POSITION_CENTER_SCREEN) { + if (p_property.name == "current_screen" && initial_position != WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -482,7 +482,11 @@ void Window::_make_window() { Rect2i window_rect; if (initial_position == WINDOW_INITIAL_POSITION_ABSOLUTE) { window_rect = Rect2i(position, size); - } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_SCREEN) { + } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN) { + window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(DisplayServer::SCREEN_PRIMARY) + (DisplayServer::get_singleton()->screen_get_size(DisplayServer::SCREEN_PRIMARY) - size) / 2, size); + } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN) { + window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(DisplayServer::SCREEN_OF_MAIN_WINDOW) + (DisplayServer::get_singleton()->screen_get_size(DisplayServer::SCREEN_OF_MAIN_WINDOW) - size) / 2, size); + } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) { window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(current_screen) + (DisplayServer::get_singleton()->screen_get_size(current_screen) - size) / 2, size); } window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, window_rect); @@ -2246,18 +2250,14 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i())); ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75)); - ADD_PROPERTY(PropertyInfo(Variant::INT, "initial_position", PROPERTY_HINT_ENUM, "Absolute,Screen Center"), "set_initial_position", "get_initial_position"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "initial_position", PROPERTY_HINT_ENUM, "Absolute,Primary Screen Center,Main Window Screen Center,Other Screen Center"), "set_initial_position", "get_initial_position"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode"); // Keep the enum values in sync with the `DisplayServer::SCREEN_` enum. - String screen_hints = "Primary Monitor:-2,Main Window Monitor:-1"; - for (int i = 0; i < 64; i++) { - screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i); - } - ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_ENUM, screen_hints), "set_current_screen", "get_current_screen"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_current_screen", "get_current_screen"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon"); @@ -2340,7 +2340,9 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL); BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_ABSOLUTE); - BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_SCREEN); + BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN); + BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN); + BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN); } Window::Window() { diff --git a/scene/main/window.h b/scene/main/window.h index d819ca7c60..e9c217f973 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -90,14 +90,16 @@ public: enum WindowInitialPosition { WINDOW_INITIAL_POSITION_ABSOLUTE, - WINDOW_INITIAL_POSITION_CENTER_SCREEN, + WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN, + WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN, + WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN, }; private: DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID; String title; - mutable int current_screen = DisplayServer::SCREEN_PRIMARY; + mutable int current_screen = 0; mutable Vector2i position; mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE); mutable Size2i min_size; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d56b94b6fe..7bebf1cfd3 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -140,6 +140,7 @@ #include "scene/main/viewport.h" #include "scene/main/window.h" #include "scene/resources/animation_library.h" +#include "scene/resources/audio_stream_polyphonic.h" #include "scene/resources/audio_stream_wav.h" #include "scene/resources/bit_map.h" #include "scene/resources/bone_map.h" @@ -907,6 +908,8 @@ void register_scene_types() { #endif GDREGISTER_ABSTRACT_CLASS(VideoStream); GDREGISTER_CLASS(AudioStreamWAV); + GDREGISTER_CLASS(AudioStreamPolyphonic); + GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackPolyphonic); OS::get_singleton()->yield(); // may take time to init diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b371266c83..50f3015814 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -4754,17 +4754,17 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol // The frame has advanced, time to validate the previous frame uint32_t current_page_size = base_page_size; - for (uint32_t i = 0; i < data_tracks.size(); i++) { - uint32_t track_size = data_tracks[i].data.size(); // track size - track_size += data_tracks[i].get_temp_packet_size(); // Add the temporary data + for (const AnimationCompressionDataState &state : data_tracks) { + uint32_t track_size = state.data.size(); // track size + track_size += state.get_temp_packet_size(); // Add the temporary data if (track_size > Compression::MAX_DATA_TRACK_SIZE) { rollback = true; //track to large, time track can't point to keys any longer, because key offset is 12 bits break; } current_page_size += track_size; } - for (uint32_t i = 0; i < time_tracks.size(); i++) { - current_page_size += time_tracks[i].packets.size() * 4; // time packet is 32 bits + for (const AnimationCompressionTimeState &state : time_tracks) { + current_page_size += state.packets.size() * 4; // time packet is 32 bits } if (!rollback && current_page_size > p_page_size) { @@ -4776,22 +4776,22 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol if (rollback) { // Not valid any longer, so rollback and commit page - for (uint32_t i = 0; i < data_tracks.size(); i++) { - data_tracks[i].temp_packets.resize(data_tracks[i].validated_packet_count); + for (AnimationCompressionDataState &state : data_tracks) { + state.temp_packets.resize(state.validated_packet_count); } - for (uint32_t i = 0; i < time_tracks.size(); i++) { - time_tracks[i].key_index = time_tracks[i].validated_key_index; //rollback key - time_tracks[i].packets.resize(time_tracks[i].validated_packet_count); + for (AnimationCompressionTimeState &state : time_tracks) { + state.key_index = state.validated_key_index; //rollback key + state.packets.resize(state.validated_packet_count); } } else { // All valid, so save rollback information - for (uint32_t i = 0; i < data_tracks.size(); i++) { - data_tracks[i].validated_packet_count = data_tracks[i].temp_packets.size(); + for (AnimationCompressionDataState &state : data_tracks) { + state.validated_packet_count = state.temp_packets.size(); } - for (uint32_t i = 0; i < time_tracks.size(); i++) { - time_tracks[i].validated_key_index = time_tracks[i].key_index; - time_tracks[i].validated_packet_count = time_tracks[i].packets.size(); + for (AnimationCompressionTimeState &state : time_tracks) { + state.validated_key_index = state.key_index; + state.validated_packet_count = state.packets.size(); } // Accept this frame as the frame being processed (as long as it exists) @@ -4976,8 +4976,8 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol } uint32_t new_size = 0; - for (uint32_t i = 0; i < compression.pages.size(); i++) { - new_size += compression.pages[i].data.size(); + for (const Compression::Page &page : compression.pages) { + new_size += page.data.size(); } print_line("Original size: " + itos(orig_size) + " - Compressed size: " + itos(new_size) + " " + String::num(float(new_size) / float(orig_size) * 100, 2) + "% pages: " + itos(compression.pages.size())); @@ -5289,8 +5289,8 @@ int Animation::_get_compressed_key_count(uint32_t p_compressed_track) const { int key_count = 0; - for (uint32_t i = 0; i < compression.pages.size(); i++) { - const uint8_t *page_data = compression.pages[i].data.ptr(); + for (const Compression::Page &page : compression.pages) { + const uint8_t *page_data = page.data.ptr(); // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported. const uint32_t *indices = (const uint32_t *)page_data; const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]]; @@ -5323,8 +5323,8 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in ERR_FAIL_COND_V(!compression.enabled, false); ERR_FAIL_UNSIGNED_INDEX_V(p_compressed_track, compression.bounds.size(), false); - for (uint32_t i = 0; i < compression.pages.size(); i++) { - const uint8_t *page_data = compression.pages[i].data.ptr(); + for (const Compression::Page &page : compression.pages) { + const uint8_t *page_data = page.data.ptr(); // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported. const uint32_t *indices = (const uint32_t *)page_data; const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]]; @@ -5374,7 +5374,7 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in } } - r_time = compression.pages[i].time_offset + double(frame) / double(compression.fps); + r_time = page.time_offset + double(frame) / double(compression.fps); for (uint32_t l = 0; l < COMPONENTS; l++) { r_value[l] = decode[l]; } diff --git a/scene/resources/audio_stream_polyphonic.cpp b/scene/resources/audio_stream_polyphonic.cpp new file mode 100644 index 0000000000..f7299b0789 --- /dev/null +++ b/scene/resources/audio_stream_polyphonic.cpp @@ -0,0 +1,274 @@ +/**************************************************************************/ +/* audio_stream_polyphonic.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "audio_stream_polyphonic.h" +#include "scene/main/scene_tree.h" + +Ref<AudioStreamPlayback> AudioStreamPolyphonic::instantiate_playback() { + Ref<AudioStreamPlaybackPolyphonic> playback; + playback.instantiate(); + playback->streams.resize(polyphony); + return playback; +} + +String AudioStreamPolyphonic::get_stream_name() const { + return "AudioStreamPolyphonic"; +} + +bool AudioStreamPolyphonic::is_monophonic() const { + return true; // This avoids stream players to instantiate more than one of these. +} + +void AudioStreamPolyphonic::set_polyphony(int p_voices) { + ERR_FAIL_COND(p_voices < 0 || p_voices > 128); + polyphony = p_voices; +} +int AudioStreamPolyphonic::get_polyphony() const { + return polyphony; +} + +void AudioStreamPolyphonic::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_polyphony", "voices"), &AudioStreamPolyphonic::set_polyphony); + ClassDB::bind_method(D_METHOD("get_polyphony"), &AudioStreamPolyphonic::get_polyphony); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "polyphony", PROPERTY_HINT_RANGE, "1,128,1"), "set_polyphony", "get_polyphony"); +} + +AudioStreamPolyphonic::AudioStreamPolyphonic() { +} + +//////////////////////// + +void AudioStreamPlaybackPolyphonic::start(double p_from_pos) { + if (active) { + stop(); + } + + active = true; +} + +void AudioStreamPlaybackPolyphonic::stop() { + if (!active) { + return; + } + + bool locked = false; + for (Stream &s : streams) { + if (s.active.is_set()) { + // Need locking because something may still be mixing. + locked = true; + AudioServer::get_singleton()->lock(); + } + s.active.clear(); + s.finish_request.clear(); + s.stream_playback.unref(); + s.stream.unref(); + } + if (locked) { + AudioServer::get_singleton()->unlock(); + } + + active = false; +} + +bool AudioStreamPlaybackPolyphonic::is_playing() const { + return active; +} + +int AudioStreamPlaybackPolyphonic::get_loop_count() const { + return 0; +} + +double AudioStreamPlaybackPolyphonic::get_playback_position() const { + return 0; +} +void AudioStreamPlaybackPolyphonic::seek(double p_time) { + // Ignored. +} + +void AudioStreamPlaybackPolyphonic::tag_used_streams() { + for (Stream &s : streams) { + if (s.active.is_set()) { + s.stream_playback->tag_used_streams(); + } + } +} + +int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { + if (!active) { + return 0; + } + + // Pre-clear buffer. + for (int i = 0; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0, 0); + } + + for (Stream &s : streams) { + if (!s.active.is_set()) { + continue; + } + + float volume_db = s.volume_db; // Copy because it can be overridden at any time. + float next_volume = Math::db_to_linear(volume_db); + s.prev_volume_db = volume_db; + + if (s.finish_request.is_set()) { + if (s.pending_play.is_set()) { + // Did not get the chance to play, was finalized too soon. + s.active.clear(); + continue; + } + next_volume = 0; + } + + if (s.pending_play.is_set()) { + s.stream_playback->start(s.play_offset); + s.pending_play.clear(); + } + float prev_volume = Math::db_to_linear(s.prev_volume_db); + + float volume_inc = (next_volume - prev_volume) / float(p_frames); + + int todo = p_frames; + int offset = 0; + float volume = prev_volume; + + bool stream_done = false; + + while (todo) { + int to_mix = MIN(todo, int(INTERNAL_BUFFER_LEN)); + int mixed = s.stream_playback->mix(internal_buffer, s.pitch_scale, to_mix); + + for (int i = 0; i < to_mix; i++) { + p_buffer[offset + i] += internal_buffer[i] * volume; + volume += volume_inc; + } + + if (mixed < to_mix) { + // Stream is done. + s.active.clear(); + stream_done = true; + break; + } + + todo -= to_mix; + offset += to_mix; + } + + if (stream_done) { + continue; + } + + if (s.finish_request.is_set()) { + s.active.clear(); + } + } + + return p_frames; +} + +AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(const Ref<AudioStream> &p_stream, float p_from_offset, float p_volume_db, float p_pitch_scale) { + ERR_FAIL_COND_V(p_stream.is_null(), INVALID_ID); + for (uint32_t i = 0; i < streams.size(); i++) { + if (!streams[i].active.is_set()) { + // Can use this stream, as it's not active. + streams[i].stream = p_stream; + streams[i].stream_playback = streams[i].stream->instantiate_playback(); + streams[i].play_offset = p_from_offset; + streams[i].volume_db = p_volume_db; + streams[i].prev_volume_db = p_volume_db; + streams[i].pitch_scale = p_pitch_scale; + streams[i].id = id_counter++; + streams[i].finish_request.clear(); + streams[i].pending_play.set(); + streams[i].active.set(); + return (ID(i) << INDEX_SHIFT) | ID(streams[i].id); + } + } + + return INVALID_ID; +} + +AudioStreamPlaybackPolyphonic::Stream *AudioStreamPlaybackPolyphonic::_find_stream(int64_t p_id) { + uint32_t index = p_id >> INDEX_SHIFT; + if (index >= streams.size()) { + return nullptr; + } + if (!streams[index].active.is_set()) { + return nullptr; // Not active, no longer exists. + } + int64_t id = p_id & ID_MASK; + if (streams[index].id != id) { + return nullptr; + } + return &streams[index]; +} + +void AudioStreamPlaybackPolyphonic::set_stream_volume(ID p_stream_id, float p_volume_db) { + Stream *s = _find_stream(p_stream_id); + if (!s) { + return; + } + s->volume_db = p_volume_db; +} + +void AudioStreamPlaybackPolyphonic::set_stream_pitch_scale(ID p_stream_id, float p_pitch_scale) { + Stream *s = _find_stream(p_stream_id); + if (!s) { + return; + } + s->pitch_scale = p_pitch_scale; +} + +bool AudioStreamPlaybackPolyphonic::is_stream_playing(ID p_stream_id) const { + return const_cast<AudioStreamPlaybackPolyphonic *>(this)->_find_stream(p_stream_id) != nullptr; +} + +void AudioStreamPlaybackPolyphonic::stop_stream(ID p_stream_id) { + Stream *s = _find_stream(p_stream_id); + if (!s) { + return; + } + s->finish_request.set(); +} + +void AudioStreamPlaybackPolyphonic::_bind_methods() { + ClassDB::bind_method(D_METHOD("play_stream", "stream", "from_offset", "volume_db", "pitch_scale"), &AudioStreamPlaybackPolyphonic::play_stream, DEFVAL(0), DEFVAL(0), DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("set_stream_volume", "stream", "volume_db"), &AudioStreamPlaybackPolyphonic::set_stream_volume); + ClassDB::bind_method(D_METHOD("set_stream_pitch_scale", "stream", "pitch_scale"), &AudioStreamPlaybackPolyphonic::set_stream_pitch_scale); + ClassDB::bind_method(D_METHOD("is_stream_playing", "stream"), &AudioStreamPlaybackPolyphonic::is_stream_playing); + ClassDB::bind_method(D_METHOD("stop_stream", "stream"), &AudioStreamPlaybackPolyphonic::stop_stream); + + BIND_CONSTANT(INVALID_ID); +} + +AudioStreamPlaybackPolyphonic::AudioStreamPlaybackPolyphonic() { +} diff --git a/scene/resources/audio_stream_polyphonic.h b/scene/resources/audio_stream_polyphonic.h new file mode 100644 index 0000000000..e414401b6f --- /dev/null +++ b/scene/resources/audio_stream_polyphonic.h @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* audio_stream_polyphonic.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef AUDIO_STREAM_POLYPHONIC_H +#define AUDIO_STREAM_POLYPHONIC_H + +#include "core/templates/local_vector.h" +#include "servers/audio/audio_stream.h" + +class AudioStreamPolyphonic : public AudioStream { + GDCLASS(AudioStreamPolyphonic, AudioStream) + int polyphony = 32; + + static void _bind_methods(); + +public: + virtual Ref<AudioStreamPlayback> instantiate_playback() override; + virtual String get_stream_name() const override; + virtual bool is_monophonic() const override; + + void set_polyphony(int p_voices); + int get_polyphony() const; + + AudioStreamPolyphonic(); +}; + +class AudioStreamPlaybackPolyphonic : public AudioStreamPlayback { + GDCLASS(AudioStreamPlaybackPolyphonic, AudioStreamPlayback) + + enum { + INTERNAL_BUFFER_LEN = 128, + ID_MASK = 0xFFFFFFFF, + INDEX_SHIFT = 32 + }; + struct Stream { + SafeFlag active; + SafeFlag pending_play; + SafeFlag finish_request; + float play_offset = 0; + float pitch_scale = 1.0; + Ref<AudioStream> stream; + Ref<AudioStreamPlayback> stream_playback; + float prev_volume_db = 0; + float volume_db = 0; + uint32_t id = 0; + + Stream() : + active(false), pending_play(false), finish_request(false) {} + }; + + LocalVector<Stream> streams; + AudioFrame internal_buffer[INTERNAL_BUFFER_LEN]; + + bool active = false; + uint32_t id_counter = 1; + + _FORCE_INLINE_ Stream *_find_stream(int64_t p_id); + + friend class AudioStreamPolyphonic; + +protected: + static void _bind_methods(); + +public: + typedef int64_t ID; + enum { + INVALID_ID = -1 + }; + + 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 double get_playback_position() const override; + virtual void seek(double p_time) override; + + virtual void tag_used_streams() override; + + virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override; + + ID play_stream(const Ref<AudioStream> &p_stream, float p_from_offset = 0, float p_volume_db = 0, float p_pitch_scale = 1.0); + void set_stream_volume(ID p_stream_id, float p_volume_db); + void set_stream_pitch_scale(ID p_stream_id, float p_pitch_scale); + bool is_stream_playing(ID p_stream_id) const; + void stop_stream(ID p_stream_id); + + AudioStreamPlaybackPolyphonic(); +}; + +#endif // AUDIO_STREAM_POLYPHONIC_H diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp index b5e302cce5..61df56523d 100644 --- a/scene/resources/camera_attributes.cpp +++ b/scene/resources/camera_attributes.cpp @@ -286,10 +286,10 @@ void CameraAttributesPractical::_bind_methods() { ADD_GROUP("DOF Blur", "dof_blur_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); ADD_GROUP("Auto Exposure", "auto_exposure_"); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 4d3eec6333..7a865691d9 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -53,7 +53,7 @@ static const int default_corner_radius = 3; static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) { Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); style->set_bg_color(p_color); - style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); + style->set_content_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); style->set_corner_radius_all(p_corner_radius); style->set_anti_aliased(true); @@ -67,10 +67,10 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = } static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float p_top, float p_right, float p_bottom) { - p_sbox->set_expand_margin_size(SIDE_LEFT, p_left * scale); - p_sbox->set_expand_margin_size(SIDE_TOP, p_top * scale); - p_sbox->set_expand_margin_size(SIDE_RIGHT, p_right * scale); - p_sbox->set_expand_margin_size(SIDE_BOTTOM, p_bottom * scale); + p_sbox->set_expand_margin(SIDE_LEFT, p_left * scale); + p_sbox->set_expand_margin(SIDE_TOP, p_top * scale); + p_sbox->set_expand_margin(SIDE_RIGHT, p_right * scale); + p_sbox->set_expand_margin(SIDE_BOTTOM, p_bottom * scale); return p_sbox; } @@ -93,7 +93,7 @@ static Ref<ImageTexture> generate_icon(int p_index) { static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBox> style(memnew(StyleBoxEmpty)); - style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); + style->set_content_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); return style; } @@ -148,7 +148,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const const Ref<StyleBoxFlat> button_disabled = make_flat_stylebox(style_disabled_color); Ref<StyleBoxFlat> focus = make_flat_stylebox(style_focus_color, default_margin, default_margin, default_margin, default_margin, default_corner_radius, false, 2); // Make the focus outline appear to be flush with the buttons it's focusing. - focus->set_expand_margin_size_all(2 * scale); + focus->set_expand_margin_all(2 * scale); theme->set_stylebox("normal", "Button", button_normal); theme->set_stylebox("hover", "Button", button_hover); @@ -279,9 +279,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CheckBox Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty); - cbx_empty->set_default_margin_all(4 * scale); + cbx_empty->set_content_margin_all(4 * scale); Ref<StyleBox> cbx_focus = focus; - cbx_focus->set_default_margin_all(4 * scale); + cbx_focus->set_content_margin_all(4 * scale); theme->set_stylebox("normal", "CheckBox", cbx_empty); theme->set_stylebox("pressed", "CheckBox", cbx_empty); @@ -317,7 +317,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CheckButton Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); - cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale); + cb_empty->set_content_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale); theme->set_stylebox("normal", "CheckButton", cb_empty); theme->set_stylebox("pressed", "CheckButton", cb_empty); @@ -634,10 +634,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine); separator_horizontal->set_thickness(Math::round(scale)); separator_horizontal->set_color(style_separator_color); - separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0); + separator_horizontal->set_content_margin_individual(default_margin, 0, default_margin, 0); Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate(); separator_vertical->set_vertical(true); - separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin); + separator_vertical->set_content_margin_individual(0, default_margin, 0, default_margin); // Always display a border for PopupMenus so they can be distinguished from their background. Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 746f2f8f9b..8b4656414d 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1043,6 +1043,18 @@ void Environment::_validate_property(PropertyInfo &p_property) const { } } + if (p_property.name == "ambient_light_color" || p_property.name == "ambient_light_energy") { + if (ambient_source == AMBIENT_SOURCE_DISABLED) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } + + if (p_property.name == "ambient_light_sky_contribution") { + if (ambient_source == AMBIENT_SOURCE_DISABLED || ambient_source == AMBIENT_SOURCE_COLOR) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } + if (p_property.name == "fog_aerial_perspective") { if (bg_mode != BG_SKY) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index 247927163b..48d609da97 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -41,8 +41,8 @@ void ImmediateMesh::surface_set_color(const Color &p_color) { if (!uses_colors) { colors.resize(vertices.size()); - for (uint32_t i = 0; i < colors.size(); i++) { - colors[i] = p_color; + for (Color &color : colors) { + color = p_color; } uses_colors = true; } @@ -54,8 +54,8 @@ void ImmediateMesh::surface_set_normal(const Vector3 &p_normal) { if (!uses_normals) { normals.resize(vertices.size()); - for (uint32_t i = 0; i < normals.size(); i++) { - normals[i] = p_normal; + for (Vector3 &normal : normals) { + normal = p_normal; } uses_normals = true; } @@ -66,8 +66,8 @@ void ImmediateMesh::surface_set_tangent(const Plane &p_tangent) { ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); if (!uses_tangents) { tangents.resize(vertices.size()); - for (uint32_t i = 0; i < tangents.size(); i++) { - tangents[i] = p_tangent; + for (Plane &tangent : tangents) { + tangent = p_tangent; } uses_tangents = true; } @@ -78,8 +78,8 @@ void ImmediateMesh::surface_set_uv(const Vector2 &p_uv) { ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); if (!uses_uvs) { uvs.resize(vertices.size()); - for (uint32_t i = 0; i < uvs.size(); i++) { - uvs[i] = p_uv; + for (Vector2 &uv : uvs) { + uv = p_uv; } uses_uvs = true; } @@ -90,8 +90,8 @@ void ImmediateMesh::surface_set_uv2(const Vector2 &p_uv2) { ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); if (!uses_uv2s) { uv2s.resize(vertices.size()); - for (uint32_t i = 0; i < uv2s.size(); i++) { - uv2s[i] = p_uv2; + for (Vector2 &uv : uv2s) { + uv = p_uv2; } uses_uv2s = true; } @@ -194,25 +194,20 @@ void ImmediateMesh::surface_end() { if (uses_normals) { uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + normal_offset]; - Vector3 n = normals[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + Vector2 n = normals[i].octahedron_encode(); uint32_t value = 0; - value |= CLAMP(int(n.x * 1023.0), 0, 1023); - value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; - value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + value |= (uint16_t)CLAMP(n.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(n.y * 65535, 0, 65535) << 16; *normal = value; } if (uses_tangents) { uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + tangent_offset]; - Plane t = tangents[i]; + Vector2 t = tangents[i].normal.octahedron_tangent_encode(tangents[i].d); uint32_t value = 0; - value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); - value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; - value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - if (t.d > 0) { - value |= 3UL << 30; - } + value |= (uint16_t)CLAMP(t.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(t.y * 65535, 0, 65535) << 16; *tangent = value; } diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index eefa5aa14a..55b633a40c 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -364,9 +364,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli const LocalVector<Pair<int, int>> &close_verts = E->value; bool found = false; - for (unsigned int k = 0; k < close_verts.size(); k++) { - const Pair<int, int> &idx = close_verts[k]; - + for (const Pair<int, int> &idx : close_verts) { bool is_uvs_close = (!uvs_ptr || uvs_ptr[j].distance_squared_to(uvs_ptr[idx.second]) < CMP_EPSILON2); bool is_uv2s_close = (!uv2s_ptr || uv2s_ptr[j].distance_squared_to(uv2s_ptr[idx.second]) < CMP_EPSILON2); ERR_FAIL_INDEX(idx.second, normals.size()); @@ -599,8 +597,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli const LocalVector<int> &corners = vertex_corners[j]; const Vector3 &vertex_normal = normals_ptr[j]; - for (unsigned int k = 0; k < corners.size(); k++) { - const int &corner_idx = corners[k]; + for (const int &corner_idx : corners) { const Vector3 &ray_normal = ray_normals[corner_idx]; if (ray_normal.length_squared() < CMP_EPSILON2) { @@ -635,8 +632,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli split_vertex_indices.push_back(j); split_vertex_normals.push_back(n); int new_idx = split_vertex_count++; - for (unsigned int l = 0; l < group_indices.size(); l++) { - new_indices_ptr[group_indices[l]] = new_idx; + for (const int &index : group_indices) { + new_indices_ptr[index] = new_idx; } } } @@ -1241,10 +1238,10 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, } //generate surfaces - for (unsigned int i = 0; i < surfaces_tools.size(); i++) { - surfaces_tools[i]->index(); - Array arrays = surfaces_tools[i]->commit_to_arrays(); - add_surface(surfaces_tools[i]->get_primitive_type(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name")); + for (Ref<SurfaceTool> &tool : surfaces_tools) { + tool->index(); + Array arrays = tool->commit_to_arrays(); + add_surface(tool->get_primitive_type(), arrays, Array(), Dictionary(), tool->get_material(), tool->get_meta("name")); } set_lightmap_size_hint(Size2(size_x, size_y)); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index d5c3f7730b..9c3a2ffb87 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -149,11 +149,36 @@ Material::~Material() { bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { if (shader.is_valid()) { - StringName pr = shader->remap_parameter(p_name); - if (pr) { - set_shader_parameter(pr, p_value); + const StringName *sn = remap_cache.getptr(p_name); + if (sn) { + set_shader_parameter(*sn, p_value); + return true; + } + String s = p_name; + if (s.begins_with("shader_parameter/")) { + String param = s.replace_first("shader_parameter/", ""); + remap_cache[s] = param; + set_shader_parameter(param, p_value); return true; } +#ifndef DISABLE_DEPRECATED + // Compatibility remaps are only needed here. + if (s.begins_with("param/")) { + s = s.replace_first("param/", "shader_parameter/"); + } else if (s.begins_with("shader_param/")) { + s = s.replace_first("shader_param/", "shader_parameter/"); + } else if (s.begins_with("shader_uniform/")) { + s = s.replace_first("shader_uniform/", "shader_parameter/"); + } else { + return false; // Not a shader parameter. + } + + WARN_PRINT("This material (containing shader with path: '" + shader->get_path() + "') uses an old deprecated parameter names. Consider re-saving this resource (or scene which contains it) in order for it to continue working in future versions."); + String param = s.replace_first("shader_parameter/", ""); + remap_cache[s] = param; + set_shader_parameter(param, p_value); + return true; +#endif } return false; @@ -161,9 +186,10 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { if (shader.is_valid()) { - StringName pr = shader->remap_parameter(p_name); - if (pr) { - r_ret = get_shader_parameter(pr); + const StringName *sn = remap_cache.getptr(p_name); + if (sn) { + // Only return a parameter if it was previously set. + r_ret = get_shader_parameter(*sn); return true; } } @@ -247,6 +273,12 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { PropertyInfo info = E->get(); info.name = "shader_parameter/" + info.name; + if (!param_cache.has(E->get().name)) { + // Property has never been edited, retrieve with default value. + Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), E->get().name); + param_cache.insert(E->get().name, default_value); + remap_cache.insert(info.name, E->get().name); + } groups[last_group][last_subgroup].push_back(info); } @@ -275,11 +307,10 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { bool ShaderMaterial::_property_can_revert(const StringName &p_name) const { if (shader.is_valid()) { - StringName pr = shader->remap_parameter(p_name); + const StringName *pr = remap_cache.getptr(p_name); if (pr) { - Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr); - Variant current_value; - _get(p_name, current_value); + Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), *pr); + Variant current_value = get_shader_parameter(*pr); return default_value.get_type() != Variant::NIL && default_value != current_value; } } @@ -288,9 +319,9 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const { bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const { if (shader.is_valid()) { - StringName pr = shader->remap_parameter(p_name); - if (pr) { - r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr); + const StringName *pr = remap_cache.getptr(p_name); + if (*pr) { + r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), *pr); return true; } } @@ -791,6 +822,14 @@ void BaseMaterial3D::_update_shader() { code += "uniform vec4 refraction_texture_channel;\n"; } + if (features[FEATURE_REFRACTION]) { + code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;"; + } + + if (proximity_fade_enabled) { + code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;"; + } + if (features[FEATURE_NORMAL_MAPPING]) { code += "uniform sampler2D texture_normal : hint_roughness_normal," + texfilter_str + ";\n"; code += "uniform float normal_scale : hint_range(-16,16);\n"; @@ -1228,7 +1267,7 @@ void BaseMaterial3D::_update_shader() { code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n"; } code += " float ref_amount = 1.0 - albedo.a * albedo_tex.a;\n"; - code += " EMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n"; + code += " EMISSION += textureLod(screen_texture,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n"; code += " ALBEDO *= 1.0 - ref_amount;\n"; code += " ALPHA = 1.0;\n"; @@ -1246,7 +1285,7 @@ void BaseMaterial3D::_update_shader() { } if (proximity_fade_enabled) { - code += " float depth_tex = textureLod(DEPTH_TEXTURE,SCREEN_UV,0.0).r;\n"; + code += " float depth_tex = textureLod(depth_texture,SCREEN_UV,0.0).r;\n"; code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);\n"; code += " world_pos.xyz/=world_pos.w;\n"; code += " ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n"; diff --git a/scene/resources/material.h b/scene/resources/material.h index f1777d31f4..83c7a09cc4 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -82,7 +82,8 @@ class ShaderMaterial : public Material { GDCLASS(ShaderMaterial, Material); Ref<Shader> shader; - HashMap<StringName, Variant> param_cache; + mutable HashMap<StringName, StringName> remap_cache; + mutable HashMap<StringName, Variant> param_cache; protected: bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 5e18b5df37..991e060e94 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -189,6 +189,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (primitive == PRIMITIVE_TRIANGLES) { for (int j = 0; j < ic; j++) { int index = ir[j]; + ERR_FAIL_COND_V(index >= vc, Ref<TriangleMesh>()); facesw[widx++] = vr[index]; } } else { // PRIMITIVE_TRIANGLE_STRIP @@ -687,6 +688,7 @@ void Mesh::_bind_methods() { BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES); BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE); BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS); + BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); @@ -1120,17 +1122,6 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } int idx = sname.substr(8, sl - 8).to_int(); - // This is a bit of a hack to ensure compatibility with older material - // overrides that start indexing at 1. - // We assume that idx 0 is always read first, if its not, this won't work. - if (idx == 0) { - surface_index_0 = true; - } - if (!surface_index_0) { - // This means the file was created when the indexing started at 1, so decrease by one. - idx--; - } - String what = sname.get_slicec('/', 1); if (what == "material") { surface_set_material(idx, p_value); @@ -1555,6 +1546,7 @@ void ArrayMesh::_recompute_aabb() { // TODO: Need to add binding to add_surface using future MeshSurfaceData object. void ArrayMesh::add_surface(BitField<ArrayFormat> p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) { + ERR_FAIL_COND(surfaces.size() == RS::MAX_MESH_SURFACES); _create_if_empty(); Surface s; @@ -1590,6 +1582,7 @@ void ArrayMesh::add_surface(BitField<ArrayFormat> p_format, PrimitiveType p_prim } void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, BitField<ArrayFormat> p_flags) { + ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX); RS::SurfaceData surface; @@ -2058,7 +2051,7 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode); ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode); - ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces); ClassDB::bind_method(D_METHOD("surface_update_vertex_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_vertex_region); ClassDB::bind_method(D_METHOD("surface_update_attribute_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_attribute_region); diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index d45b8a9295..015eb0fa45 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -139,7 +139,6 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].name = p_name; emit_changed(); - notify_property_list_changed(); } void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { @@ -155,7 +154,6 @@ void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &p_trans item_map[p_item].mesh_transform = p_transform; notify_change_to_owners(); emit_changed(); - notify_property_list_changed(); } void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) { @@ -190,7 +188,6 @@ void MeshLibrary::set_item_navigation_layers(int p_item, uint32_t p_navigation_l notify_property_list_changed(); notify_change_to_owners(); emit_changed(); - notify_property_list_changed(); } void MeshLibrary::set_item_preview(int p_item, const Ref<Texture2D> &p_preview) { diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index b0c2f1d7f5..e497a628aa 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -402,8 +402,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } } - for (uint32_t i = 0; i < deferred_node_paths.size(); i++) { - const DeferredNodePathProperties &dnp = deferred_node_paths[i]; + for (const DeferredNodePathProperties &dnp : deferred_node_paths) { Node *other = dnp.base->get_node_or_null(dnp.path); dnp.base->set(dnp.property, other); } diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index 85106883f9..3bbd0a0b5e 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -325,7 +325,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector } const Point &np = points[least_cost_point]; - //open the neighbours for search + //open the neighbors for search for (const int &E : np.connections) { Point &p = points.write[E]; @@ -339,7 +339,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector p.distance = distance; } } else { - //add to open neighbours + //add to open neighbors p.prev = least_cost_point; p.distance = distance; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 5ef66a22b6..86ed0001dd 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -2901,7 +2901,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i))); } - Array stt; + TypedArray<Vector3i> stt; if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) { GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt); } else { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 22cd12b004..e62f26b17c 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -622,7 +622,7 @@ protected: virtual void _create_mesh_array(Array &p_arr) const override; public: - GDVIRTUAL2RC(Array, _structured_text_parser, Array, String) + GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String) TextMesh(); ~TextMesh(); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 80b9ff3f38..0ba177f882 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -49,10 +49,6 @@ /// -void ResourceLoaderText::set_local_path(const String &p_local_path) { - res_path = p_local_path; -} - Ref<Resource> ResourceLoaderText::get_resource() { return resource; } @@ -927,7 +923,11 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String if (is_scene) { fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); } else { - fw->store_line("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); + String script_res_text; + if (!script_class.is_empty()) { + script_res_text = "script_class=\"" + script_class + "\" "; + } + fw->store_line("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); } } @@ -1051,6 +1051,10 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) { return; } + if (tag.fields.has("script_class")) { + script_class = tag.fields["script_class"]; + } + res_type = tag.fields["type"]; } else { @@ -1497,6 +1501,44 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) { return OK; } +String ResourceLoaderText::recognize_script_class(Ref<FileAccess> p_f) { + error = OK; + + lines = 1; + f = p_f; + + stream.f = f; + + ignore_resource_parsing = true; + + VariantParser::Tag tag; + Error err = VariantParser::parse_tag(&stream, lines, error_text, tag); + + if (err) { + _printerr(); + return ""; + } + + if (tag.fields.has("format")) { + int fmt = tag.fields["format"]; + if (fmt > FORMAT_VERSION) { + error_text = "Saved with newer format version"; + _printerr(); + return ""; + } + } + + if (tag.name != "gd_resource") { + return ""; + } + + if (tag.fields.has("script_class")) { + return tag.fields["script_class"]; + } + + return ""; +} + String ResourceLoaderText::recognize(Ref<FileAccess> p_f) { error = OK; @@ -1666,6 +1708,25 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const { return ClassDB::get_compatibility_remapped_class(r); } +String ResourceFormatLoaderText::get_resource_script_class(const String &p_path) const { + String ext = p_path.get_extension().to_lower(); + if (ext != "tres") { + return String(); + } + + // ...for anything else must test... + + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { + return ""; //could not read + } + + ResourceLoaderText loader; + loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); + loader.res_path = loader.local_path; + return loader.recognize_script_class(f); +} + ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) const { String ext = p_path.get_extension().to_lower(); @@ -1846,6 +1907,9 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, List<Variant> keys; d.get_key_list(&keys); for (const Variant &E : keys) { + // Of course keys should also be cached, after all we can't prevent users from using resources as keys, right? + // See also ResourceFormatSaverBinaryInstance::_find_resources (when p_variant is of type Variant::DICTIONARY) + _find_resources(E); Variant v = d[E]; _find_resources(v); } @@ -1906,7 +1970,12 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource "; if (packed_scene.is_null()) { title += "type=\"" + _resource_get_class(p_resource) + "\" "; + Ref<Script> script = p_resource->get_script(); + if (script.is_valid() && script->get_global_name()) { + title += "script_class=\"" + String(script->get_global_name()) + "\" "; + } } + int load_steps = saved_resources.size() + external_resources.size(); if (load_steps > 1) { @@ -2245,7 +2314,12 @@ Error ResourceLoaderText::set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid) { if (is_scene) { fw->store_string("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]"); } else { - fw->store_string("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]"); + String script_res_text; + if (!script_class.is_empty()) { + script_res_text = "script_class=\"" + script_class + "\" "; + } + + fw->store_string("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]"); } uint8_t c = f->get_8(); diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 0f95e2fbfd..25001d8023 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -64,6 +64,7 @@ class ResourceLoaderText { int resources_total = 0; int resource_current = 0; String resource_type; + String script_class; VariantParser::Tag next_tag; @@ -115,7 +116,6 @@ class ResourceLoaderText { Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser); public: - void set_local_path(const String &p_local_path); Ref<Resource> get_resource(); Error load(); Error set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid); @@ -125,6 +125,7 @@ public: void open(Ref<FileAccess> p_f, bool p_skip_first_tag = false); String recognize(Ref<FileAccess> p_f); + String recognize_script_class(Ref<FileAccess> p_f); ResourceUID::ID get_uid(Ref<FileAccess> p_f); void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types); Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map); @@ -144,6 +145,7 @@ public: virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); virtual String get_resource_type(const String &p_path) const; + virtual String get_resource_script_class(const String &p_path) const; virtual ResourceUID::ID get_resource_uid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map); diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 9bb2db17ab..b3952e745f 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -43,7 +43,6 @@ Shader::Mode Shader::get_mode() const { void Shader::_dependency_changed() { RenderingServer::get_singleton()->shader_set_code(shader, RenderingServer::get_singleton()->shader_get_code(shader)); - params_cache_dirty = true; emit_changed(); } @@ -93,7 +92,6 @@ void Shader::set_code(const String &p_code) { } RenderingServer::get_singleton()->shader_set_code(shader, pp_code); - params_cache_dirty = true; emit_changed(); } @@ -108,8 +106,6 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr List<PropertyInfo> local; RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local); - params_cache.clear(); - params_cache_dirty = false; for (PropertyInfo &pi : local) { bool is_group = pi.usage == PROPERTY_USAGE_GROUP || pi.usage == PROPERTY_USAGE_SUBGROUP; @@ -120,7 +116,6 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr if (default_textures.has(pi.name)) { //do not show default textures continue; } - params_cache[pi.name] = pi.name; } if (p_params) { //small little hack @@ -176,11 +171,17 @@ bool Shader::is_text_shader() const { return true; } -bool Shader::has_parameter(const StringName &p_name) const { - return params_cache.has(p_name); +void Shader::_update_shader() const { } -void Shader::_update_shader() const { +Array Shader::_get_shader_uniform_list(bool p_get_groups) { + List<PropertyInfo> uniform_list; + get_shader_uniform_list(&uniform_list, p_get_groups); + Array ret; + for (const PropertyInfo &pi : uniform_list) { + ret.push_back(pi.operator Dictionary()); + } + return ret; } void Shader::_bind_methods() { @@ -192,7 +193,7 @@ void Shader::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_texture_parameter", "name", "texture", "index"), &Shader::set_default_texture_parameter, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_default_texture_parameter", "name", "index"), &Shader::get_default_texture_parameter, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("has_parameter", "name"), &Shader::has_parameter); + ClassDB::bind_method(D_METHOD("get_shader_uniform_list", "get_groups"), &Shader::_get_shader_uniform_list, DEFVAL(false)); ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code"); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index e579c2fca1..75c490e912 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -57,15 +57,12 @@ private: HashSet<Ref<ShaderInclude>> include_dependencies; String code; - // hack the name of performance - // shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make - // conversion fast and save memory. - mutable bool params_cache_dirty = true; - mutable HashMap<StringName, StringName> params_cache; //map a shader param to a material param.. HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures; void _dependency_changed(); virtual void _update_shader() const; //used for visual shader + Array _get_shader_uniform_list(bool p_get_groups = false); + protected: static void _bind_methods(); @@ -79,7 +76,6 @@ public: String get_code() const; void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const; - bool has_parameter(const StringName &p_name) const; void set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index = 0); Ref<Texture2D> get_default_texture_parameter(const StringName &p_name, int p_index = 0) const; @@ -87,47 +83,6 @@ public: virtual bool is_text_shader() const; - // Finds the shader parameter name for the given property name, which should start with "shader_parameter/". - _FORCE_INLINE_ StringName remap_parameter(const StringName &p_property) const { - if (params_cache_dirty) { - get_shader_uniform_list(nullptr); - } - - String n = p_property; - - // Backwards compatibility with old shader parameter names. - // Note: The if statements are important to make sure we are only replacing text exactly at index 0. - if (n.find("param/") == 0) { - n = n.replace_first("param/", "shader_parameter/"); - } - if (n.find("shader_param/") == 0) { - n = n.replace_first("shader_param/", "shader_parameter/"); - } - if (n.find("shader_uniform/") == 0) { - n = n.replace_first("shader_uniform/", "shader_parameter/"); - } - - { - // Additional backwards compatibility for projects between #62972 and #64092 (about a month of v4.0 development). - // These projects did not have any prefix for shader uniforms due to a bug. - // This code should be removed during beta or rc of 4.0. - const HashMap<StringName, StringName>::Iterator E = params_cache.find(n); - if (E) { - return E->value; - } - } - - if (n.begins_with("shader_parameter/")) { - n = n.replace_first("shader_parameter/", ""); - const HashMap<StringName, StringName>::Iterator E = params_cache.find(n); - if (E) { - return E->value; - } - } - - return StringName(); - } - virtual RID get_rid() const override; Shader(); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 6390850b24..4f16986392 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -34,76 +34,65 @@ #include <limits.h> -float StyleBox::get_style_margin(Side p_side) const { - float ret = 0; - GDVIRTUAL_REQUIRED_CALL(_get_style_margin, p_side, ret); - return ret; -} +Size2 StyleBox::get_minimum_size() const { + Size2 min_size = Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM)); + Size2 custom_size; + GDVIRTUAL_CALL(_get_minimum_size, custom_size); -bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { - bool ret = true; - GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret); - return ret; -} + if (min_size.x < custom_size.x) { + min_size.x = custom_size.x; + } + if (min_size.y < custom_size.y) { + min_size.y = custom_size.y; + } -void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const { - GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect); + return min_size; } -void StyleBox::set_default_margin(Side p_side, float p_value) { +void StyleBox::set_content_margin(Side p_side, float p_value) { ERR_FAIL_INDEX((int)p_side, 4); - margin[p_side] = p_value; + content_margin[p_side] = p_value; emit_changed(); } -void StyleBox::set_default_margin_all(float p_value) { +void StyleBox::set_content_margin_all(float p_value) { for (int i = 0; i < 4; i++) { - margin[i] = p_value; + content_margin[i] = p_value; } emit_changed(); } -void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { - margin[SIDE_LEFT] = p_left; - margin[SIDE_TOP] = p_top; - margin[SIDE_RIGHT] = p_right; - margin[SIDE_BOTTOM] = p_bottom; +void StyleBox::set_content_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { + content_margin[SIDE_LEFT] = p_left; + content_margin[SIDE_TOP] = p_top; + content_margin[SIDE_RIGHT] = p_right; + content_margin[SIDE_BOTTOM] = p_bottom; emit_changed(); } -float StyleBox::get_default_margin(Side p_side) const { +float StyleBox::get_content_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_side]; + return content_margin[p_side]; } float StyleBox::get_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - if (margin[p_side] < 0) { + if (content_margin[p_side] < 0) { return get_style_margin(p_side); } else { - return margin[p_side]; + return content_margin[p_side]; } } -CanvasItem *StyleBox::get_current_item_drawn() const { - return CanvasItem::get_current_item_drawn(); -} - -Size2 StyleBox::get_minimum_size() const { - return Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM)); -} - Point2 StyleBox::get_offset() const { return Point2(get_margin(SIDE_LEFT), get_margin(SIDE_TOP)); } -Size2 StyleBox::get_center_size() const { - Size2 ret; - GDVIRTUAL_CALL(_get_center_size, ret); - return ret; +void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const { + GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect); } Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const { @@ -114,37 +103,46 @@ Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const { return p_rect; } +CanvasItem *StyleBox::get_current_item_drawn() const { + return CanvasItem::get_current_item_drawn(); +} + +bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { + bool ret = true; + GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret); + return ret; +} + void StyleBox::_bind_methods() { - ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask); + ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size); - ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin); - ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all); - ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin); + ClassDB::bind_method(D_METHOD("set_content_margin", "margin", "offset"), &StyleBox::set_content_margin); + ClassDB::bind_method(D_METHOD("set_content_margin_all", "offset"), &StyleBox::set_content_margin_all); + ClassDB::bind_method(D_METHOD("get_content_margin", "margin"), &StyleBox::get_content_margin); ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin); - ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size); - ClassDB::bind_method(D_METHOD("get_center_size"), &StyleBox::get_center_size); ClassDB::bind_method(D_METHOD("get_offset"), &StyleBox::get_offset); - ClassDB::bind_method(D_METHOD("get_current_item_drawn"), &StyleBox::get_current_item_drawn); ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw); + ClassDB::bind_method(D_METHOD("get_current_item_drawn"), &StyleBox::get_current_item_drawn); + + ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask); ADD_GROUP("Content Margins", "content_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_BOTTOM); - GDVIRTUAL_BIND(_get_style_margin, "side") - GDVIRTUAL_BIND(_test_mask, "point", "rect") - GDVIRTUAL_BIND(_get_center_size) - GDVIRTUAL_BIND(_get_draw_rect, "rect") GDVIRTUAL_BIND(_draw, "to_canvas_item", "rect") + GDVIRTUAL_BIND(_get_draw_rect, "rect") + GDVIRTUAL_BIND(_get_minimum_size) + GDVIRTUAL_BIND(_test_mask, "point", "rect") } StyleBox::StyleBox() { for (int i = 0; i < 4; i++) { - margin[i] = -1; + content_margin[i] = -1; } } @@ -165,38 +163,38 @@ Ref<Texture2D> StyleBoxTexture::get_texture() const { return texture; } -void StyleBoxTexture::set_margin_size(Side p_side, float p_size) { +void StyleBoxTexture::set_texture_margin(Side p_side, float p_size) { ERR_FAIL_INDEX((int)p_side, 4); - margin[p_side] = p_size; + texture_margin[p_side] = p_size; emit_changed(); } -void StyleBoxTexture::set_margin_size_all(float p_size) { +void StyleBoxTexture::set_texture_margin_all(float p_size) { for (int i = 0; i < 4; i++) { - margin[i] = p_size; + texture_margin[i] = p_size; } emit_changed(); } -void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { - margin[SIDE_LEFT] = p_left; - margin[SIDE_TOP] = p_top; - margin[SIDE_RIGHT] = p_right; - margin[SIDE_BOTTOM] = p_bottom; +void StyleBoxTexture::set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { + texture_margin[SIDE_LEFT] = p_left; + texture_margin[SIDE_TOP] = p_top; + texture_margin[SIDE_RIGHT] = p_right; + texture_margin[SIDE_BOTTOM] = p_bottom; emit_changed(); } -float StyleBoxTexture::get_margin_size(Side p_side) const { +float StyleBoxTexture::get_texture_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_side]; + return texture_margin[p_side]; } float StyleBoxTexture::get_style_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_side]; + return texture_margin[p_side]; } Rect2 StyleBoxTexture::get_draw_rect(const Rect2 &p_rect) const { @@ -218,7 +216,10 @@ void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const { rect.size.x += expand_margin[SIDE_LEFT] + expand_margin[SIDE_RIGHT]; rect.size.y += expand_margin[SIDE_TOP] + expand_margin[SIDE_BOTTOM]; - RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate); + Vector2 start_offset = Vector2(texture_margin[SIDE_LEFT], texture_margin[SIDE_TOP]); + Vector2 end_offset = Vector2(texture_margin[SIDE_RIGHT], texture_margin[SIDE_BOTTOM]); + + RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), start_offset, end_offset, RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate); } void StyleBoxTexture::set_draw_center(bool p_enabled) { @@ -230,21 +231,29 @@ bool StyleBoxTexture::is_draw_center_enabled() const { return draw_center; } -Size2 StyleBoxTexture::get_center_size() const { - if (texture.is_null()) { - return Size2(); +Size2 StyleBoxTexture::get_minimum_size() const { + Size2 min_size = StyleBox::get_minimum_size(); + + // Make sure that the min size is no smaller than the used texture region. + if (texture.is_valid()) { + if (min_size.x < region_rect.size.x) { + min_size.x = region_rect.size.x; + } + if (min_size.y < region_rect.size.y) { + min_size.y = region_rect.size.y; + } } - return region_rect.size - get_minimum_size(); + return min_size; } -void StyleBoxTexture::set_expand_margin_size(Side p_side, float p_size) { +void StyleBoxTexture::set_expand_margin(Side p_side, float p_size) { ERR_FAIL_INDEX((int)p_side, 4); expand_margin[p_side] = p_size; emit_changed(); } -void StyleBoxTexture::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { +void StyleBoxTexture::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { expand_margin[SIDE_LEFT] = p_left; expand_margin[SIDE_TOP] = p_top; expand_margin[SIDE_RIGHT] = p_right; @@ -252,14 +261,14 @@ void StyleBoxTexture::set_expand_margin_size_individual(float p_left, float p_to emit_changed(); } -void StyleBoxTexture::set_expand_margin_size_all(float p_expand_margin_size) { +void StyleBoxTexture::set_expand_margin_all(float p_expand_margin_size) { for (int i = 0; i < 4; i++) { expand_margin[i] = p_expand_margin_size; } emit_changed(); } -float StyleBoxTexture::get_expand_margin_size(Side p_side) const { +float StyleBoxTexture::get_expand_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0); return expand_margin[p_side]; } @@ -313,13 +322,13 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &StyleBoxTexture::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture); - ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size); - ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all); - ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size); + ClassDB::bind_method(D_METHOD("set_texture_margin", "margin", "size"), &StyleBoxTexture::set_texture_margin); + ClassDB::bind_method(D_METHOD("set_texture_margin_all", "size"), &StyleBoxTexture::set_texture_margin_all); + ClassDB::bind_method(D_METHOD("get_texture_margin", "margin"), &StyleBoxTexture::get_texture_margin); - ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size); - ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all); - ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size); + ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxTexture::set_expand_margin); + ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_all); + ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxTexture::get_expand_margin); ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect); ClassDB::bind_method(D_METHOD("get_region_rect"), &StyleBoxTexture::get_region_rect); @@ -338,17 +347,17 @@ void StyleBoxTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_GROUP("Margins", "margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_BOTTOM); + ADD_GROUP("Texture Margins", "texture_margin_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_BOTTOM); ADD_GROUP("Expand Margins", "expand_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM); ADD_GROUP("Axis Stretch", "axis_stretch_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode"); @@ -450,13 +459,13 @@ int StyleBoxFlat::get_corner_radius(const Corner p_corner) const { return corner_radius[p_corner]; } -void StyleBoxFlat::set_expand_margin_size(Side p_side, float p_size) { +void StyleBoxFlat::set_expand_margin(Side p_side, float p_size) { ERR_FAIL_INDEX((int)p_side, 4); expand_margin[p_side] = p_size; emit_changed(); } -void StyleBoxFlat::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { +void StyleBoxFlat::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { expand_margin[SIDE_LEFT] = p_left; expand_margin[SIDE_TOP] = p_top; expand_margin[SIDE_RIGHT] = p_right; @@ -464,14 +473,14 @@ void StyleBoxFlat::set_expand_margin_size_individual(float p_left, float p_top, emit_changed(); } -void StyleBoxFlat::set_expand_margin_size_all(float p_expand_margin_size) { +void StyleBoxFlat::set_expand_margin_all(float p_expand_margin_size) { for (int i = 0; i < 4; i++) { expand_margin[i] = p_expand_margin_size; } emit_changed(); } -float StyleBoxFlat::get_expand_margin_size(Side p_side) const { +float StyleBoxFlat::get_expand_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); return expand_margin[p_side]; } @@ -549,10 +558,6 @@ int StyleBoxFlat::get_corner_detail() const { return corner_detail; } -Size2 StyleBoxFlat::get_center_size() const { - return Size2(); -} - inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const real_t corner_radius[4], real_t *inner_corner_radius) { real_t border_left = inner_rect.position.x - style_rect.position.x; real_t border_top = inner_rect.position.y - style_rect.position.y; @@ -891,9 +896,9 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius); ClassDB::bind_method(D_METHOD("get_corner_radius", "corner"), &StyleBoxFlat::get_corner_radius); - ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size); - ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all); - ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size); + ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin); + ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_all); + ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin); ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center); ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxFlat::is_draw_center_enabled); @@ -1041,10 +1046,6 @@ float StyleBoxLine::get_style_margin(Side p_side) const { return 0; } -Size2 StyleBoxLine::get_center_size() const { - return Size2(); -} - void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const { RenderingServer *vs = RenderingServer::get_singleton(); Rect2i r = p_rect; diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 5a80b4d4e2..91033617ab 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -41,36 +41,34 @@ class StyleBox : public Resource { GDCLASS(StyleBox, Resource); RES_BASE_EXTENSION("stylebox"); OBJ_SAVE_TYPE(StyleBox); - float margin[4]; + float content_margin[4]; protected: - virtual float get_style_margin(Side p_side) const; + virtual float get_style_margin(Side p_side) const { return 0; } static void _bind_methods(); - GDVIRTUAL1RC(float, _get_style_margin, Side) - GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2) - GDVIRTUAL0RC(Size2, _get_center_size) - GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2) GDVIRTUAL2C(_draw, RID, Rect2) + GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2) + GDVIRTUAL0RC(Size2, _get_minimum_size) + GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2) public: - virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; + virtual Size2 get_minimum_size() const; - void set_default_margin(Side p_side, float p_value); - void set_default_margin_all(float p_value); - void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_default_margin(Side p_side) const; + void set_content_margin(Side p_side, float p_value); + void set_content_margin_all(float p_value); + void set_content_margin_individual(float p_left, float p_top, float p_right, float p_bottom); + float get_content_margin(Side p_side) const; float get_margin(Side p_side) const; - virtual Size2 get_center_size() const; + Point2 get_offset() const; - virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const; + virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; CanvasItem *get_current_item_drawn() const; - Size2 get_minimum_size() const; - Point2 get_offset() const; + virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; StyleBox(); }; @@ -96,7 +94,7 @@ public: private: float expand_margin[4] = {}; - float margin[4] = {}; + float texture_margin[4] = {}; Rect2 region_rect; Ref<Texture2D> texture; bool draw_center = true; @@ -109,15 +107,17 @@ protected: static void _bind_methods(); public: - void set_expand_margin_size(Side p_expand_side, float p_size); - void set_expand_margin_size_all(float p_expand_margin_size); - void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_expand_margin_size(Side p_expand_side) const; + virtual Size2 get_minimum_size() const override; - void set_margin_size(Side p_side, float p_size); - void set_margin_size_all(float p_size); - void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_margin_size(Side p_side) const; + void set_expand_margin(Side p_expand_side, float p_size); + void set_expand_margin_all(float p_expand_margin_size); + void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom); + float get_expand_margin(Side p_expand_side) const; + + void set_texture_margin(Side p_side, float p_size); + void set_texture_margin_all(float p_size); + void set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom); + float get_texture_margin(Side p_side) const; void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; @@ -127,7 +127,6 @@ public: void set_draw_center(bool p_enabled); bool is_draw_center_enabled() const; - virtual Size2 get_center_size() const override; void set_h_axis_stretch_mode(AxisStretchMode p_mode); AxisStretchMode get_h_axis_stretch_mode() const; @@ -198,10 +197,10 @@ public: void set_corner_detail(const int &p_corner_detail); int get_corner_detail() const; - void set_expand_margin_size(Side p_expand_side, float p_size); - void set_expand_margin_size_all(float p_expand_margin_size); - void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_expand_margin_size(Side p_expand_side) const; + void set_expand_margin(Side p_expand_side, float p_size); + void set_expand_margin_all(float p_expand_margin_size); + void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom); + float get_expand_margin(Side p_expand_side) const; void set_draw_center(bool p_enabled); bool is_draw_center_enabled() const; @@ -223,8 +222,6 @@ public: void set_aa_size(const real_t p_aa_size); real_t get_aa_size() const; - virtual Size2 get_center_size() const override; - virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override; virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override; @@ -261,8 +258,6 @@ public: void set_grow_end(float p_grow); float get_grow_end() const; - virtual Size2 get_center_size() const override; - virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override; StyleBoxLine(); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index e802e1c2d9..17e92ddfca 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -732,13 +732,13 @@ void SurfaceTool::index() { LocalVector<Vertex> old_vertex_array = vertex_array; vertex_array.clear(); - for (uint32_t i = 0; i < old_vertex_array.size(); i++) { - int *idxptr = indices.getptr(old_vertex_array[i]); + for (const Vertex &vertex : old_vertex_array) { + int *idxptr = indices.getptr(vertex); int idx; if (!idxptr) { idx = indices.size(); - vertex_array.push_back(old_vertex_array[i]); - indices[old_vertex_array[i]] = idx; + vertex_array.push_back(vertex); + indices[vertex] = idx; } else { idx = *idxptr; } @@ -756,9 +756,8 @@ void SurfaceTool::deindex() { LocalVector<Vertex> old_vertex_array = vertex_array; vertex_array.clear(); - for (uint32_t i = 0; i < index_array.size(); i++) { - uint32_t index = index_array[i]; - ERR_FAIL_COND(index >= old_vertex_array.size()); + for (const int &index : index_array) { + ERR_FAIL_COND(uint32_t(index) >= old_vertex_array.size()); vertex_array.push_back(old_vertex_array[index]); } format &= ~Mesh::ARRAY_FORMAT_INDEX; @@ -1000,8 +999,7 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const } int vfrom = vertex_array.size(); - for (uint32_t vi = 0; vi < nvertices.size(); vi++) { - Vertex v = nvertices[vi]; + for (Vertex &v : nvertices) { v.vertex = p_xform.xform(v.vertex); if (nformat & RS::ARRAY_FORMAT_NORMAL) { v.normal = p_xform.basis.xform(v.normal); @@ -1014,8 +1012,8 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const vertex_array.push_back(v); } - for (uint32_t i = 0; i < nindices.size(); i++) { - int dst_index = nindices[i] + vfrom; + for (const int &index : nindices) { + int dst_index = index + vfrom; index_array.push_back(dst_index); } if (index_array.size() % 3) { @@ -1132,9 +1130,9 @@ void SurfaceTool::generate_tangents() { TangentGenerationContextUserData triangle_data; triangle_data.vertices = &vertex_array; - for (uint32_t i = 0; i < vertex_array.size(); i++) { - vertex_array[i].binormal = Vector3(); - vertex_array[i].tangent = Vector3(); + for (Vertex &vertex : vertex_array) { + vertex.binormal = Vector3(); + vertex.tangent = Vector3(); } triangle_data.indices = &index_array; msc.m_pUserData = &triangle_data; @@ -1176,12 +1174,12 @@ void SurfaceTool::generate_normals(bool p_flip) { } } - for (uint32_t vi = 0; vi < vertex_array.size(); vi++) { - Vector3 *lv = vertex_hash.getptr(vertex_array[vi]); + for (Vertex &vertex : vertex_array) { + Vector3 *lv = vertex_hash.getptr(vertex); if (!lv) { - vertex_array[vi].normal = Vector3(); + vertex.normal = Vector3(); } else { - vertex_array[vi].normal = lv->normalized(); + vertex.normal = lv->normalized(); } } diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index 6d66c48b78..dfafc7d2bc 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -135,8 +135,8 @@ void TextParagraph::_bind_methods() { void TextParagraph::_shape_lines() { if (lines_dirty) { - for (int i = 0; i < (int)lines_rid.size(); i++) { - TS->free_rid(lines_rid[i]); + for (const RID &line_rid : lines_rid) { + TS->free_rid(line_rid); } lines_rid.clear(); @@ -234,14 +234,14 @@ void TextParagraph::_shape_lines() { } else { // Autowrap disabled. - for (int i = 0; i < (int)lines_rid.size(); i++) { + for (const RID &line_rid : lines_rid) { if (alignment == HORIZONTAL_ALIGNMENT_FILL) { - TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags); + TS->shaped_text_fit_to_width(line_rid, width, jst_flags); overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE); - TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags); - TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS); + TS->shaped_text_overrun_trim_to_width(line_rid, width, overrun_flags); + TS->shaped_text_fit_to_width(line_rid, width, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS); } else { - TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags); + TS->shaped_text_overrun_trim_to_width(line_rid, width, overrun_flags); } } } @@ -268,8 +268,8 @@ RID TextParagraph::get_dropcap_rid() const { void TextParagraph::clear() { _THREAD_SAFE_METHOD_ - for (int i = 0; i < (int)lines_rid.size(); i++) { - TS->free_rid(lines_rid[i]); + for (const RID &line_rid : lines_rid) { + TS->free_rid(line_rid); } lines_rid.clear(); TS->shaped_text_clear(rid); @@ -915,17 +915,17 @@ int TextParagraph::hit_test(const Point2 &p_coords) const { return 0; } } - for (int i = 0; i < (int)lines_rid.size(); i++) { - if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) { - if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) { - return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x); + for (const RID &line_rid : lines_rid) { + if (TS->shaped_text_get_orientation(line_rid) == TextServer::ORIENTATION_HORIZONTAL) { + if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(line_rid).y)) { + return TS->shaped_text_hit_test_position(line_rid, p_coords.x); } - ofs.y += TS->shaped_text_get_size(lines_rid[i]).y; + ofs.y += TS->shaped_text_get_size(line_rid).y; } else { - if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines_rid[i]).x)) { - return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.y); + if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(line_rid).x)) { + return TS->shaped_text_hit_test_position(line_rid, p_coords.y); } - ofs.y += TS->shaped_text_get_size(lines_rid[i]).x; + ofs.y += TS->shaped_text_get_size(line_rid).x; } } return TS->shaped_text_get_range(rid).y; @@ -1027,8 +1027,8 @@ TextParagraph::TextParagraph() { } TextParagraph::~TextParagraph() { - for (int i = 0; i < (int)lines_rid.size(); i++) { - TS->free_rid(lines_rid[i]); + for (const RID &line_rid : lines_rid) { + TS->free_rid(line_rid); } lines_rid.clear(); TS->free_rid(rid); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 94e78fc3aa..b5a68ef14b 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -404,8 +404,8 @@ void TileSet::_update_terrains_cache() { if (terrains_cache_dirty) { // Organizes tiles into structures. per_terrain_pattern_tiles.resize(terrain_sets.size()); - for (int i = 0; i < (int)per_terrain_pattern_tiles.size(); i++) { - per_terrain_pattern_tiles[i].clear(); + for (RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>> &tiles : per_terrain_pattern_tiles) { + tiles.clear(); } for (const KeyValue<int, Ref<TileSetSource>> &kv : sources) { @@ -1342,8 +1342,8 @@ void TileSet::clear_tile_proxies() { int TileSet::add_pattern(Ref<TileMapPattern> p_pattern, int p_index) { ERR_FAIL_COND_V(!p_pattern.is_valid(), -1); ERR_FAIL_COND_V_MSG(p_pattern->is_empty(), -1, "Cannot add an empty pattern to the TileSet."); - for (unsigned int i = 0; i < patterns.size(); i++) { - ERR_FAIL_COND_V_MSG(patterns[i] == p_pattern, -1, "TileSet has already this pattern."); + for (const Ref<TileMapPattern> &pattern : patterns) { + ERR_FAIL_COND_V_MSG(pattern == p_pattern, -1, "TileSet has already this pattern."); } ERR_FAIL_COND_V(p_index > (int)patterns.size(), -1); if (p_index < 0) { @@ -4190,8 +4190,8 @@ real_t TileSetAtlasSource::get_tile_animation_total_duration(const Vector2i p_at ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); real_t sum = 0.0; - for (int frame = 0; frame < (int)tiles[p_atlas_coords].animation_frames_durations.size(); frame++) { - sum += tiles[p_atlas_coords].animation_frames_durations[frame]; + for (const real_t &duration : tiles[p_atlas_coords].animation_frames_durations) { + sum += duration; } return sum; } @@ -4573,8 +4573,8 @@ void TileSetAtlasSource::_clear_tiles_outside_texture() { } } - for (unsigned int i = 0; i < to_remove.size(); i++) { - remove_tile(to_remove[i]); + for (const Vector2i &v : to_remove) { + remove_tile(v); } } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 4c99563a91..1cbeaae428 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -399,7 +399,6 @@ void VisualShaderNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded"); - ADD_SIGNAL(MethodInfo("editor_refresh_request")); BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR); BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR_INT); @@ -2734,9 +2733,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "front_facing", "FRONT_FACING" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_roughness_texture", "NORMAL_ROUGHNESS_TEXTURE" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" }, @@ -2799,7 +2795,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" }, diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 432d5a5b59..e78d9b924d 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -756,141 +756,157 @@ Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture::get_default_t } String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - if (source == SOURCE_TEXTURE) { - String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "tex"); - switch (texture_type) { - case TYPE_DATA: - break; - case TYPE_COLOR: - u += " : source_color"; - break; - case TYPE_NORMAL_MAP: - u += " : hint_normal"; - break; - default: - break; - } - return u + ";\n"; + String code; + + switch (source) { + case SOURCE_TEXTURE: { + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "tex"); + switch (texture_type) { + case TYPE_DATA: { + } break; + case TYPE_COLOR: { + code += " : source_color"; + } break; + case TYPE_NORMAL_MAP: { + code += " : hint_normal"; + } break; + default: { + } break; + } + code += ";\n"; + } break; + case SOURCE_SCREEN: { + if ((p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "screen_tex") + " : hint_screen_texture;\n"; + } + } break; + case SOURCE_DEPTH: + case SOURCE_3D_NORMAL: + case SOURCE_ROUGHNESS: { + if (p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { + String sampler_name = ""; + String hint = " : "; + if (source == SOURCE_DEPTH) { + sampler_name = "depth_tex"; + hint += "hint_depth_texture;\n"; + } else { + sampler_name = source == SOURCE_ROUGHNESS ? "roughness_tex" : "normal_roughness_tex"; + hint += "hint_normal_roughness_texture;\n"; + } + code += "uniform sampler2D " + make_unique_id(p_type, p_id, sampler_name) + hint; + } + } break; + default: { + } break; } - return String(); + return code; } String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String default_uv; if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { - default_uv = "UV"; + if (source == SOURCE_SCREEN) { + default_uv = "SCREEN_UV"; + } else { + default_uv = "UV"; + } } else { default_uv = "vec2(0.0)"; } String code; - if (source == SOURCE_TEXTURE) { - String id = make_unique_id(p_type, p_id, "tex"); - if (p_input_vars[0].is_empty()) { // Use UV by default. + String uv = p_input_vars[0].is_empty() ? default_uv : p_input_vars[0]; + + switch (source) { + case SOURCE_PORT: + case SOURCE_TEXTURE: { + String id; + if (source == SOURCE_PORT) { + id = p_input_vars[2]; + if (id.is_empty()) { + break; + } + } else { // SOURCE_TEXTURE + id = make_unique_id(p_type, p_id, "tex"); + } if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n"; + code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n"; } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n"; } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; - } - return code; - } - - if (source == SOURCE_PORT) { - String id = p_input_vars[2]; - if (id.is_empty()) { - code += " " + p_output_vars[0] + " = vec4(0.0);\n"; - } else { - if (p_input_vars[0].is_empty()) { // Use UV by default. + return code; + } break; + case SOURCE_SCREEN: { + if ((p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { + String id = make_unique_id(p_type, p_id, "screen_tex"); if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n"; + code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n"; } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n"; } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; - } - } - return code; - } - - if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { - if (p_input_vars[0].is_empty() || p_for_preview) { // Use UV by default. - if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0);\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; + return code; } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", 0.0);\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; - } - return code; - } + } break; + case SOURCE_2D_NORMAL: + case SOURCE_2D_TEXTURE: { + if (p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { + String id = source == SOURCE_2D_TEXTURE ? "TEXTURE" : "NORMAL_TEXTURE"; - if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { - if (p_input_vars[0].is_empty()) { // Use UV by default. - if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = texture(TEXTURE, " + default_uv + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; + if (p_input_vars[1].is_empty()) { + code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n"; + } else { + code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n"; + } + return code; } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = texture(TEXTURE, " + p_input_vars[0] + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; - } - return code; - } + } break; + case SOURCE_3D_NORMAL: + case SOURCE_ROUGHNESS: + case SOURCE_DEPTH: { + if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { + String var_name = ""; + String sampler_name = ""; + + switch (source) { + case SOURCE_DEPTH: { + var_name = "_depth"; + sampler_name = "depth_tex"; + } break; + case SOURCE_ROUGHNESS: { + var_name = "_roughness"; + sampler_name = "roughness_tex"; + } break; + case SOURCE_3D_NORMAL: { + var_name = "_normal"; + sampler_name = "normal_roughness_tex"; + } break; + default: { + } break; + } - if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { - if (p_input_vars[0].is_empty()) { // Use UV by default. - if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = texture(NORMAL_TEXTURE, " + default_uv + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; - } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = texture(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy);\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; - } - return code; - } + String id = make_unique_id(p_type, p_id, sampler_name); + String type = source == SOURCE_3D_NORMAL ? "vec3" : "float"; + String components = source == SOURCE_3D_NORMAL ? "rgb" : "r"; - if (source == SOURCE_DEPTH) { - if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { - code += " {\n"; - if (p_input_vars[0].is_empty()) { // Use UV by default. + code += " {\n"; if (p_input_vars[1].is_empty()) { - code += " float _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n"; + code += " " + type + " " + var_name + " = texture(" + id + ", " + uv + ")." + components + ";\n"; } else { - code += " float _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n"; + code += " " + type + " " + var_name + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ")." + components + ";\n"; } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " float _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n"; - } else { - code += " float _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n"; - } + if (source == SOURCE_3D_NORMAL) { + code += " " + p_output_vars[0] + " = vec4(" + var_name + ", 1.0);\n"; + } else { + code += " " + p_output_vars[0] + " = vec4(" + var_name + ", " + var_name + ", " + var_name + ", 1.0);\n"; + } + code += " }\n"; - code += " " + p_output_vars[0] + " = vec4(_depth, _depth, _depth, 1.0);\n"; - code += " }\n"; - return code; - } + return code; + } + } break; + default: { + } break; } code += " " + p_output_vars[0] + " = vec4(0.0);\n"; @@ -921,12 +937,17 @@ void VisualShaderNodeTexture::set_source(Source p_source) { case SOURCE_PORT: simple_decl = false; break; + case SOURCE_3D_NORMAL: + simple_decl = false; + break; + case SOURCE_ROUGHNESS: + simple_decl = false; + break; default: break; } source = p_source; emit_changed(); - emit_signal(SNAME("editor_refresh_request")); } VisualShaderNodeTexture::Source VisualShaderNodeTexture::get_source() const { @@ -970,31 +991,34 @@ String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::T return RTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'."); } - if (source == SOURCE_TEXTURE) { - return String(); // all good - } - - if (source == SOURCE_PORT) { - return String(); // all good - } - - if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { - return String(); // all good - } - - if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { - return String(); // all good - } - - if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM) { - return String(); // all good - } - - if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { - if (get_output_port_for_preview() == 0) { // DEPTH_TEXTURE is not supported in preview(canvas_item) shader - return RTR("Invalid source for preview."); - } - return String(); // all good + switch (source) { + case SOURCE_TEXTURE: + case SOURCE_PORT: { + return String(); // All good. + } break; + case SOURCE_SCREEN: { + if ((p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { + return String(); // All good. + } + } break; + case SOURCE_2D_NORMAL: + case SOURCE_2D_TEXTURE: { + if (p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { + return String(); // All good. + } + } break; + case SOURCE_3D_NORMAL: + case SOURCE_ROUGHNESS: + case SOURCE_DEPTH: { + if (p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { + if (get_output_port_for_preview() == 0) { // Not supported in preview(canvas_item) shader. + return RTR("Invalid source for preview."); + } + return String(); // All good. + } + } break; + default: { + } break; } return RTR("Invalid source for shader."); @@ -1010,7 +1034,7 @@ void VisualShaderNodeTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type); ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort"), "set_source", "get_source"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort,Normal3D,Roughness"), "set_source", "get_source"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map"), "set_texture_type", "get_texture_type"); @@ -1020,6 +1044,8 @@ void VisualShaderNodeTexture::_bind_methods() { BIND_ENUM_CONSTANT(SOURCE_2D_NORMAL); BIND_ENUM_CONSTANT(SOURCE_DEPTH); BIND_ENUM_CONSTANT(SOURCE_PORT); + BIND_ENUM_CONSTANT(SOURCE_3D_NORMAL); + BIND_ENUM_CONSTANT(SOURCE_ROUGHNESS); BIND_ENUM_CONSTANT(SOURCE_MAX); BIND_ENUM_CONSTANT(TYPE_DATA); @@ -1260,6 +1286,17 @@ bool VisualShaderNodeSample3D::is_input_port_default(int p_port, Shader::Mode p_ } String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + String id; + if (source == SOURCE_TEXTURE) { + id = make_unique_id(p_type, p_id, "tex3d"); + } else { // SOURCE_PORT + id = p_input_vars[2]; + if (id.is_empty()) { + code += " " + p_output_vars[0] + " = vec4(0.0);\n"; + return code; + } + } String default_uv; if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { default_uv = "vec3(UV, 0.0)"; @@ -1267,33 +1304,12 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader default_uv = "vec3(0.0)"; } - String code; - if (source == SOURCE_TEXTURE || source == SOURCE_PORT) { - String id; - if (source == SOURCE_TEXTURE) { - id = make_unique_id(p_type, p_id, "tex3d"); - } else { - id = p_input_vars[2]; - } - if (!id.is_empty()) { - if (p_input_vars[0].is_empty()) { // Use UV by default. - if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; - } - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; - } - } else { - code += " " + p_output_vars[0] + " = vec4(0.0);\n"; - } - return code; + String uv = p_input_vars[0].is_empty() ? default_uv : p_input_vars[0]; + if (p_input_vars[1].is_empty()) { + code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n"; + } else { + code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n"; } - code += " " + p_output_vars[0] + " = vec4(0.0);\n"; return code; } @@ -1304,7 +1320,6 @@ void VisualShaderNodeSample3D::set_source(Source p_source) { } source = p_source; emit_changed(); - emit_signal(SNAME("editor_refresh_request")); } VisualShaderNodeSample3D::Source VisualShaderNodeSample3D::get_source() const { @@ -1326,14 +1341,7 @@ String VisualShaderNodeSample3D::get_warning(Shader::Mode p_mode, VisualShader:: if (is_input_port_connected(2) && source != SOURCE_PORT) { return RTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'."); } - - if (source == SOURCE_TEXTURE) { - return String(); // all good - } - if (source == SOURCE_PORT) { - return String(); // all good - } - return RTR("Invalid source for shader."); + return String(); } VisualShaderNodeSample3D::VisualShaderNodeSample3D() { @@ -1539,42 +1547,33 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade } String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - String default_uv; - if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { - default_uv = "vec3(UV, 0.0)"; - } else { - default_uv = "vec3(0.0)"; - } - String code; String id; + if (source == SOURCE_TEXTURE) { id = make_unique_id(p_type, p_id, "cube"); - } else if (source == SOURCE_PORT) { + } else { // SOURCE_PORT id = p_input_vars[2]; - } else { - return code; + if (id.is_empty()) { + code += " " + p_output_vars[0] + " = vec4(0.0);\n"; + return code; + } } - if (id.is_empty()) { - code += " " + p_output_vars[0] + " = vec4(0.0);\n"; - return code; + String default_uv; + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + default_uv = "vec3(UV, 0.0)"; + } else { + default_uv = "vec3(0.0)"; } - if (p_input_vars[0].is_empty()) { // Use UV by default. - - if (p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n"; - } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; - } - - } else if (p_input_vars[1].is_empty()) { - //no lod - code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n"; + String uv = p_input_vars[0].is_empty() ? default_uv : p_input_vars[0]; + if (p_input_vars[1].is_empty()) { + code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n"; } else { - code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n"; } + return code; } @@ -1594,7 +1593,6 @@ void VisualShaderNodeCubemap::set_source(Source p_source) { } source = p_source; emit_changed(); - emit_signal(SNAME("editor_refresh_request")); } VisualShaderNodeCubemap::Source VisualShaderNodeCubemap::get_source() const { @@ -1702,11 +1700,15 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const return false; } +String VisualShaderNodeLinearSceneDepth::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture;\n"; +} + String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += " {\n"; - code += " float __log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n"; + code += " float __log_depth = textureLod(" + make_unique_id(p_type, p_id, "depth_tex") + ", SCREEN_UV, 0.0).x;\n"; code += " vec3 __depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, __log_depth);\n"; code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(__depth_ndc, 1.0);\n"; code += " __depth_view.xyz /= __depth_view.w;\n"; @@ -6101,7 +6103,7 @@ VisualShaderNodeTransformParameter::VisualShaderNodeTransformParameter() { ////////////// -String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat) { +String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat, VisualShaderNodeTextureParameter::TextureSource p_texture_source) { String code; bool has_colon = false; @@ -6204,6 +6206,33 @@ String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_ } } + { + String source_code; + + switch (p_texture_source) { + case VisualShaderNodeTextureParameter::SOURCE_SCREEN: + source_code = "hint_screen_texture"; + break; + case VisualShaderNodeTextureParameter::SOURCE_DEPTH: + source_code = "hint_depth_texture"; + break; + case VisualShaderNodeTextureParameter::SOURCE_NORMAL_ROUGHNESS: + source_code = "hint_normal_roughness_texture"; + break; + default: + break; + } + + if (!source_code.is_empty()) { + if (!has_colon) { + code += " : "; + } else { + code += ", "; + } + code += source_code; + } + } + return code; } @@ -6290,6 +6319,19 @@ VisualShaderNodeTextureParameter::TextureRepeat VisualShaderNodeTextureParameter return texture_repeat; } +void VisualShaderNodeTextureParameter::set_texture_source(TextureSource p_source) { + ERR_FAIL_INDEX(int(p_source), int(SOURCE_MAX)); + if (texture_source == p_source) { + return; + } + texture_source = p_source; + emit_changed(); +} + +VisualShaderNodeTextureParameter::TextureSource VisualShaderNodeTextureParameter::get_texture_source() const { + return texture_source; +} + Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() const { Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("texture_type"); @@ -6298,6 +6340,7 @@ Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() c } props.push_back("texture_filter"); props.push_back("texture_repeat"); + props.push_back("texture_source"); return props; } @@ -6311,6 +6354,7 @@ HashMap<StringName, String> VisualShaderNodeTextureParameter::get_editable_prope names.insert("color_default", RTR("Default Color")); names.insert("texture_filter", RTR("Filter")); names.insert("texture_repeat", RTR("Repeat")); + names.insert("texture_source", RTR("Source")); return names; } @@ -6318,19 +6362,23 @@ void VisualShaderNodeTextureParameter::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureParameter::set_texture_type); ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureParameter::get_texture_type); - ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureParameter::set_color_default); + ClassDB::bind_method(D_METHOD("set_color_default", "color"), &VisualShaderNodeTextureParameter::set_color_default); ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureParameter::get_color_default); ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureParameter::set_texture_filter); ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureParameter::get_texture_filter); - ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureParameter::set_texture_repeat); + ClassDB::bind_method(D_METHOD("set_texture_repeat", "repeat"), &VisualShaderNodeTextureParameter::set_texture_repeat); ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureParameter::get_texture_repeat); + ClassDB::bind_method(D_METHOD("set_texture_source", "source"), &VisualShaderNodeTextureParameter::set_texture_source); + ClassDB::bind_method(D_METHOD("get_texture_source"), &VisualShaderNodeTextureParameter::get_texture_source); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_source", PROPERTY_HINT_ENUM, "None,Screen,Depth,NormalRoughness"), "set_texture_source", "get_texture_source"); BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); @@ -6356,6 +6404,12 @@ void VisualShaderNodeTextureParameter::_bind_methods() { BIND_ENUM_CONSTANT(REPEAT_ENABLED); BIND_ENUM_CONSTANT(REPEAT_DISABLED); BIND_ENUM_CONSTANT(REPEAT_MAX); + + BIND_ENUM_CONSTANT(SOURCE_NONE); + BIND_ENUM_CONSTANT(SOURCE_SCREEN); + BIND_ENUM_CONSTANT(SOURCE_DEPTH); + BIND_ENUM_CONSTANT(SOURCE_NORMAL_ROUGHNESS); + BIND_ENUM_CONSTANT(SOURCE_MAX); } bool VisualShaderNodeTextureParameter::is_qualifier_supported(Qualifier p_qual) const { @@ -6396,7 +6450,7 @@ String VisualShaderNodeTexture2DParameter::get_output_port_name(int p_port) cons String VisualShaderNodeTexture2DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name(); - code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source); code += ";\n"; return code; } @@ -6407,7 +6461,7 @@ VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() { ////////////// Texture Parameter (Triplanar) String VisualShaderNodeTextureParameterTriplanar::get_caption() const { - return "TextureUniformTriplanar"; + return "TextureParameterTriplanar"; } int VisualShaderNodeTextureParameterTriplanar::get_input_port_count() const { @@ -6496,7 +6550,7 @@ String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shade String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name(); - code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source); code += ";\n"; return code; } @@ -6542,7 +6596,7 @@ String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port) String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name(); - code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source); code += ";\n"; return code; } @@ -6562,7 +6616,7 @@ String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) cons String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name(); - code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source); code += ";\n"; return code; } @@ -6582,7 +6636,7 @@ String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name(); - code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source); code += ";\n"; return code; } @@ -7640,12 +7694,15 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const { return false; } +String VisualShaderNodeProximityFade::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture;\n"; +} + String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += " {\n"; - String proximity_fade_distance = vformat("%s", p_input_vars[0]); - code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n"; + code += " float __depth_tex = texture(" + make_unique_id(p_type, p_id, "depth_tex") + ", SCREEN_UV).r;\n"; if (!RenderingServer::get_singleton()->is_low_end()) { code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n"; } else { diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 07843c0264..e3b101cf84 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -385,6 +385,8 @@ public: SOURCE_2D_NORMAL, SOURCE_DEPTH, SOURCE_PORT, + SOURCE_3D_NORMAL, + SOURCE_ROUGHNESS, SOURCE_MAX, }; @@ -668,6 +670,7 @@ public: virtual String get_output_port_name(int p_port) const override; virtual bool has_output_port_preview(int p_port) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; VisualShaderNodeLinearSceneDepth(); @@ -2362,11 +2365,20 @@ public: REPEAT_MAX, }; + enum TextureSource { + SOURCE_NONE, + SOURCE_SCREEN, + SOURCE_DEPTH, + SOURCE_NORMAL_ROUGHNESS, + SOURCE_MAX, + }; + protected: TextureType texture_type = TYPE_DATA; ColorDefault color_default = COLOR_DEFAULT_WHITE; TextureFilter texture_filter = FILTER_DEFAULT; TextureRepeat texture_repeat = REPEAT_DEFAULT; + TextureSource texture_source = SOURCE_NONE; protected: static void _bind_methods(); @@ -2398,6 +2410,9 @@ public: void set_texture_repeat(TextureRepeat p_repeat); TextureRepeat get_texture_repeat() const; + void set_texture_source(TextureSource p_source); + TextureSource get_texture_source() const; + bool is_qualifier_supported(Qualifier p_qual) const override; bool is_convertible_to_constant() const override; @@ -2408,6 +2423,7 @@ VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureType) VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::ColorDefault) VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureFilter) VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureRepeat) +VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureSource) /////////////////////////////////////// @@ -2833,6 +2849,7 @@ public: virtual String get_output_port_name(int p_port) const override; virtual bool has_output_port_preview(int p_port) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; VisualShaderNodeProximityFade(); diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp index 88f2040d17..e5678914fe 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/servers/physics_3d/gjk_epa.cpp @@ -1011,9 +1011,11 @@ bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transfor if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) { if (p_result_callback) { if (p_swap) { - p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, p_userdata); + Vector3 normal = (res.witnesses[1] - res.witnesses[0]).normalized(); + p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, normal, p_userdata); } else { - p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata); + Vector3 normal = (res.witnesses[0] - res.witnesses[1]).normalized(); + p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, normal, p_userdata); } } return true; diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp index ce3da390cb..619e6c00be 100644 --- a/servers/physics_3d/godot_body_pair_3d.cpp +++ b/servers/physics_3d/godot_body_pair_3d.cpp @@ -38,12 +38,12 @@ #define MIN_VELOCITY 0.0001 #define MAX_BIAS_ROTATION (Math_PI / 8) -void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { GodotBodyPair3D *pair = static_cast<GodotBodyPair3D *>(p_userdata); - pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B); + pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal); } -void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { +void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) { Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A); Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B); @@ -577,12 +577,12 @@ GodotBodyPair3D::~GodotBodyPair3D() { B->remove_constraint(this); } -void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { GodotBodySoftBodyPair3D *pair = static_cast<GodotBodySoftBodyPair3D *>(p_userdata); - pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B); + pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal); } -void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { +void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) { Vector3 local_A = body->get_inv_transform().xform(p_point_A); Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B); @@ -591,7 +591,7 @@ void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, i contact.index_B = p_index_B; contact.local_A = local_A; contact.local_B = local_B; - contact.normal = (p_point_A - p_point_B).normalized(); + contact.normal = (normal.dot((p_point_A - p_point_B)) < 0 ? -normal : normal); contact.used = true; // Attempt to determine if the contact will be reused. diff --git a/servers/physics_3d/godot_body_pair_3d.h b/servers/physics_3d/godot_body_pair_3d.h index c3165c7fcf..a8f5180dd5 100644 --- a/servers/physics_3d/godot_body_pair_3d.h +++ b/servers/physics_3d/godot_body_pair_3d.h @@ -97,9 +97,9 @@ class GodotBodyPair3D : public GodotBodyContact3D { Contact contacts[MAX_CONTACTS]; int contact_count = 0; - static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); - void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B); + void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal); void validate_contacts(); bool _test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A, const Transform3D &p_xform_A, GodotBody3D *p_B, int p_shape_B, const Transform3D &p_xform_B); @@ -126,9 +126,9 @@ class GodotBodySoftBodyPair3D : public GodotBodyContact3D { LocalVector<Contact> contacts; - static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); - void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B); + void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal); void validate_contacts(); diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp index 0b92b745fe..fb5a67c008 100644 --- a/servers/physics_3d/godot_collision_solver_3d.cpp +++ b/servers/physics_3d/godot_collision_solver_3d.cpp @@ -81,9 +81,11 @@ bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_s if (p_result_callback) { if (p_swap_result) { - p_result_callback(supports[i], 0, support_A, 0, p_userdata); + Vector3 normal = (support_A - supports[i]).normalized(); + p_result_callback(supports[i], 0, support_A, 0, normal, p_userdata); } else { - p_result_callback(support_A, 0, supports[i], 0, p_userdata); + Vector3 normal = (supports[i] - support_A).normalized(); + p_result_callback(support_A, 0, supports[i], 0, normal, p_userdata); } } } @@ -126,9 +128,11 @@ bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A, if (p_result_callback) { if (p_swap_result) { - p_result_callback(support_B, 0, support_A, 0, p_userdata); + Vector3 normal = (support_B - support_A).normalized(); + p_result_callback(support_B, 0, support_A, 0, normal, p_userdata); } else { - p_result_callback(support_A, 0, support_B, 0, p_userdata); + Vector3 normal = (support_A - support_B).normalized(); + p_result_callback(support_A, 0, support_B, 0, normal, p_userdata); } } return true; @@ -142,7 +146,7 @@ struct _SoftBodyContactCollisionInfo { int contact_count = 0; }; -void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { _SoftBodyContactCollisionInfo &cinfo = *(static_cast<_SoftBodyContactCollisionInfo *>(p_userdata)); ++cinfo.contact_count; @@ -152,9 +156,9 @@ void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A } if (cinfo.swap_result) { - cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata); + cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, -normal, cinfo.userdata); } else { - cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata); + cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, normal, cinfo.userdata); } } diff --git a/servers/physics_3d/godot_collision_solver_3d.h b/servers/physics_3d/godot_collision_solver_3d.h index 7ef0dc97ac..36ea79576e 100644 --- a/servers/physics_3d/godot_collision_solver_3d.h +++ b/servers/physics_3d/godot_collision_solver_3d.h @@ -35,11 +35,11 @@ class GodotCollisionSolver3D { public: - typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); private: static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata); - static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); static bool soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex); static bool concave_callback(void *p_userdata, GodotShape3D *p_convex); static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0); diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index d13f4ee801..2cb29b3dd0 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -75,11 +75,13 @@ struct _CollectorCallback { Vector3 normal; Vector3 *prev_axis = nullptr; - _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) { + _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B, Vector3 p_normal) { + if (p_normal.dot(p_point_B - p_point_A) < 0) + p_normal = -p_normal; if (swap) { - callback(p_point_B, 0, p_point_A, 0, userdata); + callback(p_point_B, 0, p_point_A, 0, -p_normal, userdata); } else { - callback(p_point_A, 0, p_point_B, 0, userdata); + callback(p_point_A, 0, p_point_B, 0, p_normal, userdata); } } }; @@ -92,7 +94,7 @@ static void _generate_contacts_point_point(const Vector3 *p_points_A, int p_poin ERR_FAIL_COND(p_point_count_B != 1); #endif - p_callback->call(*p_points_A, *p_points_B); + p_callback->call(*p_points_A, *p_points_B, p_callback->normal); } static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -102,7 +104,7 @@ static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point #endif Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B); - p_callback->call(*p_points_A, closest_B); + p_callback->call(*p_points_A, closest_B, p_callback->normal); } static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -111,9 +113,9 @@ static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point ERR_FAIL_COND(p_point_count_B < 3); #endif - Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A); - - p_callback->call(*p_points_A, closest_B); + Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]); + Vector3 closest_B = plane.project(*p_points_A); + p_callback->call(*p_points_A, closest_B, plane.get_normal()); } static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -122,9 +124,9 @@ static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_poi ERR_FAIL_COND(p_point_count_B != 3); #endif - Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A); - - p_callback->call(*p_points_A, closest_B); + Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]); + Vector3 closest_B = plane.project(*p_points_A); + p_callback->call(*p_points_A, closest_B, plane.get_normal()); } static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -154,8 +156,8 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ sa.sort(dvec, 4); //use the middle ones as contacts - p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1]); - p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2]); + p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1], p_callback->normal); + p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2], p_callback->normal); return; } @@ -170,7 +172,14 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ Vector3 closest_A = p_points_A[0] + rel_A * d; Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(closest_A, p_points_B); - p_callback->call(closest_A, closest_B); + // The normal should be perpendicular to both edges. + Vector3 normal = rel_A.cross(rel_B); + real_t normal_len = normal.length(); + if (normal_len > 1e-3) + normal /= normal_len; + else + normal = p_callback->normal; + p_callback->call(closest_A, closest_B, normal); } static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -267,7 +276,7 @@ static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_poin continue; } - p_callback->call(contact_point_A, closest_B); + p_callback->call(contact_point_A, closest_B, circle_plane.get_normal()); } } @@ -352,7 +361,7 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ continue; } - p_callback->call(clipbuf_src[i], closest_B); + p_callback->call(clipbuf_src[i], closest_B, plane_B.get_normal()); } } @@ -431,7 +440,7 @@ static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_poin continue; } - p_callback->call(contact_point_A, closest_B); + p_callback->call(contact_point_A, closest_B, circle_plane.get_normal()); } } @@ -534,7 +543,7 @@ static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_po continue; } - p_callback->call(contact_point_A, closest_B); + p_callback->call(contact_point_A, closest_B, circle_B_plane.get_normal()); } } @@ -678,7 +687,7 @@ public: return true; } - static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { + static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata; Vector3 axis = (p_point_B - p_point_A); real_t depth = axis.length(); @@ -802,11 +811,11 @@ static void analytic_sphere_collision(const Vector3 &p_origin_a, real_t p_radius if (p_radius_a < p_radius_b) { Vector3 point_a = p_origin_a - b_to_a * p_radius_a; Vector3 point_b = point_a + b_to_a * overlap; - p_collector->call(point_a, point_b); // Consider adding b_to_a vector + p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector } else { Vector3 point_b = p_origin_b + b_to_a * p_radius_b; Vector3 point_a = point_b - b_to_a * overlap; - p_collector->call(point_a, point_b); // Consider adding b_to_a vector + p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector } } @@ -818,9 +827,9 @@ static void _collision_sphere_sphere(const GodotShape3D *p_a, const Transform3D // Perform an analytic sphere collision between the two spheres analytic_sphere_collision<withMargin>( p_transform_a.origin, - sphere_A->get_radius(), + sphere_A->get_radius() * p_transform_a.basis[0].length(), p_transform_b.origin, - sphere_B->get_radius(), + sphere_B->get_radius() * p_transform_b.basis[0].length(), p_collector, p_margin_a, p_margin_b); @@ -833,7 +842,7 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ // Find the point on the box nearest to the center of the sphere. - Vector3 center = p_transform_b.xform_inv(p_transform_a.origin); + Vector3 center = p_transform_b.affine_inverse().xform(p_transform_a.origin); Vector3 extents = box_B->get_half_extents(); Vector3 nearest(MIN(MAX(center.x, -extents.x), extents.x), MIN(MAX(center.y, -extents.y), extents.y), @@ -844,7 +853,8 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ Vector3 delta = nearest - p_transform_a.origin; real_t length = delta.length(); - if (length > sphere_A->get_radius() + p_margin_a + p_margin_b) { + real_t radius = sphere_A->get_radius() * p_transform_a.basis[0].length(); + if (length > radius + p_margin_a + p_margin_b) { return; } p_collector->collided = true; @@ -858,9 +868,9 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ } else { axis = delta / length; } - Vector3 point_a = p_transform_a.origin + (sphere_A->get_radius() + p_margin_a) * axis; - Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest); - p_collector->call(point_a, point_b); + Vector3 point_a = p_transform_a.origin + (radius + p_margin_a) * axis; + Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest); + p_collector->call(point_a, point_b, axis); } template <bool withMargin> @@ -868,11 +878,12 @@ static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - real_t capsule_B_radius = capsule_B->get_radius(); + real_t scale_A = p_transform_a.basis[0].length(); + real_t scale_B = p_transform_b.basis[0].length(); // Construct the capsule segment (ball-center to ball-center) Vector3 capsule_segment[2]; - Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B_radius); + Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); capsule_segment[0] = p_transform_b.origin + capsule_axis; capsule_segment[1] = p_transform_b.origin - capsule_axis; @@ -882,9 +893,9 @@ static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D // Perform an analytic sphere collision between the sphere and the sphere-collider in the capsule analytic_sphere_collision<withMargin>( p_transform_a.origin, - sphere_A->get_radius(), + sphere_A->get_radius() * scale_A, capsule_closest, - capsule_B_radius, + capsule_B->get_radius() * scale_B, p_collector, p_margin_a, p_margin_b); @@ -894,12 +905,12 @@ template <bool withMargin> static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radius_b, real_t p_height_b, const Transform3D &p_transform_a, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { // Find the point on the cylinder nearest to the center of the sphere. - Vector3 center = p_transform_b.xform_inv(p_transform_a.origin); + Vector3 center = p_transform_b.affine_inverse().xform(p_transform_a.origin); Vector3 nearest = center; - real_t radius = p_radius_b; + real_t scale_A = p_transform_a.basis[0].length(); real_t r = Math::sqrt(center.x * center.x + center.z * center.z); - if (r > radius) { - real_t scale = radius / r; + if (r > p_radius_b) { + real_t scale = p_radius_b / r; nearest.x *= scale; nearest.z *= scale; } @@ -911,7 +922,7 @@ static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radiu Vector3 delta = nearest - p_transform_a.origin; real_t length = delta.length(); - if (length > p_radius_a + p_margin_a + p_margin_b) { + if (length > p_radius_a * scale_A + p_margin_a + p_margin_b) { return; } p_collector->collided = true; @@ -925,9 +936,9 @@ static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radiu } else { axis = delta / length; } - Vector3 point_a = p_transform_a.origin + (p_radius_a + p_margin_a) * axis; - Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest); - p_collector->call(point_a, point_b); + Vector3 point_a = p_transform_a.origin + (p_radius_a * scale_A + p_margin_a) * axis; + Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest); + p_collector->call(point_a, point_b, axis); } template <bool withMargin> @@ -1623,14 +1634,14 @@ static void _collision_capsule_capsule(const GodotShape3D *p_a, const Transform3 const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - real_t capsule_A_radius = capsule_A->get_radius(); - real_t capsule_B_radius = capsule_B->get_radius(); + real_t scale_A = p_transform_a.basis[0].length(); + real_t scale_B = p_transform_b.basis[0].length(); // Get the closest points between the capsule segments Vector3 capsule_A_closest; Vector3 capsule_B_closest; - Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A_radius); - Vector3 capsule_B_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B_radius); + Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius()); + Vector3 capsule_B_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); Geometry3D::get_closest_points_between_segments( p_transform_a.origin + capsule_A_axis, p_transform_a.origin - capsule_A_axis, @@ -1642,9 +1653,9 @@ static void _collision_capsule_capsule(const GodotShape3D *p_a, const Transform3 // Perform the analytic collision between the two closest capsule spheres analytic_sphere_collision<withMargin>( capsule_A_closest, - capsule_A_radius, + capsule_A->get_radius() * scale_A, capsule_B_closest, - capsule_B_radius, + capsule_B->get_radius() * scale_B, p_collector, p_margin_a, p_margin_b); diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index e8250acb45..b6d8acfbf3 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -1737,7 +1737,7 @@ void GodotPhysicsServer3D::_update_shapes() { } } -void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { CollCbkData *cbk = static_cast<CollCbkData *>(p_userdata); if (cbk->max == 0) { diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h index 3da0c6debe..040e673dcd 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -77,7 +77,7 @@ public: Vector3 *ptr = nullptr; }; - static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); virtual RID world_boundary_shape_create() override; virtual RID separation_ray_shape_create() override; diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index 8aacfa929f..300dca4e08 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -852,17 +852,12 @@ Vector3 GodotConvexPolygonShape3D::get_support(const Vector3 &p_normal) const { // Get the array of vertices const Vector3 *const vertices_array = mesh.vertices.ptr(); - // Get the array of extreme vertices - const int *const extreme_array = extreme_vertices.ptr(); - const uint32_t extreme_size = extreme_vertices.size(); - - // Start with an initial assumption of the first extreme vertex - int best_vertex = extreme_array[0]; + // Start with an initial assumption of the first extreme vertex. + int best_vertex = extreme_vertices[0]; real_t max_support = p_normal.dot(vertices_array[best_vertex]); - // Check the remaining extreme vertices for a better vertex - for (uint32_t i = 0; i < extreme_size; ++i) { - int vert = extreme_array[i]; + // Check the remaining extreme vertices for a better vertex. + for (const int &vert : extreme_vertices) { real_t s = p_normal.dot(vertices_array[vert]); if (s > max_support) { best_vertex = vert; @@ -870,27 +865,18 @@ Vector3 GodotConvexPolygonShape3D::get_support(const Vector3 &p_normal) const { } } - // If we checked all vertices in the mesh then we're done - if (extreme_size == mesh.vertices.size()) { + // If we checked all vertices in the mesh then we're done. + if (extreme_vertices.size() == mesh.vertices.size()) { return vertices_array[best_vertex]; } - // Get the array of neighbor arrays for each vertex - const LocalVector<int> *const vertex_neighbors_array = vertex_neighbors.ptr(); - // Move along the surface until we reach the true support vertex. int last_vertex = -1; while (true) { int next_vertex = -1; - // Get the array of neighbors around the best vertex - const LocalVector<int> &neighbors = vertex_neighbors_array[best_vertex]; - const int *const neighbors_array = neighbors.ptr(); - const uint32_t neighbors_size = neighbors.size(); - - // Iterate over all the neighbors checking for a better vertex - for (uint32_t i = 0; i < neighbors_size; ++i) { - int vert = neighbors_array[i]; + // Iterate over all the neighbors checking for a better vertex. + for (const int &vert : vertex_neighbors[best_vertex]) { if (vert != last_vertex) { real_t s = p_normal.dot(vertices_array[vert]); if (s > max_support) { @@ -1149,8 +1135,7 @@ void GodotConvexPolygonShape3D::_setup(const Vector<Vector3> &p_vertices) { if (extreme_vertices.size() < mesh.vertices.size()) { vertex_neighbors.resize(mesh.vertices.size()); - for (uint32_t i = 0; i < mesh.edges.size(); i++) { - Geometry3D::MeshData::Edge &edge = mesh.edges[i]; + for (Geometry3D::MeshData::Edge &edge : mesh.edges) { vertex_neighbors[edge.vertex_a].push_back(edge.vertex_b); vertex_neighbors[edge.vertex_b].push_back(edge.vertex_a); } diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 871017a5e7..1820a29553 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -167,14 +167,11 @@ void GodotSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHand } void GodotSoftBody3D::update_normals_and_centroids() { - uint32_t i, ni; - - for (i = 0, ni = nodes.size(); i < ni; ++i) { - nodes[i].n = Vector3(); + for (Node &node : nodes) { + node.n = Vector3(); } - for (i = 0, ni = faces.size(); i < ni; ++i) { - Face &face = faces[i]; + for (Face &face : faces) { const Vector3 n = vec3_cross(face.n[0]->x - face.n[2]->x, face.n[0]->x - face.n[1]->x); face.n[0]->n += n; face.n[1]->n += n; @@ -184,8 +181,7 @@ void GodotSoftBody3D::update_normals_and_centroids() { face.centroid = 0.33333333333 * (face.n[0]->x + face.n[1]->x + face.n[2]->x); } - for (i = 0, ni = nodes.size(); i < ni; ++i) { - Node &node = nodes[i]; + for (Node &node : nodes) { real_t len = node.n.length(); if (len > CMP_EPSILON) { node.n /= len; @@ -235,9 +231,7 @@ void GodotSoftBody3D::update_area() { int i, ni; // Face area. - for (i = 0, ni = faces.size(); i < ni; ++i) { - Face &face = faces[i]; - + for (Face &face : faces) { const Vector3 &x0 = face.n[0]->x; const Vector3 &x1 = face.n[1]->x; const Vector3 &x2 = face.n[2]->x; @@ -255,12 +249,11 @@ void GodotSoftBody3D::update_area() { memset(counts.ptr(), 0, counts.size() * sizeof(int)); } - for (i = 0, ni = nodes.size(); i < ni; ++i) { - nodes[i].area = 0.0; + for (Node &node : nodes) { + node.area = 0.0; } - for (i = 0, ni = faces.size(); i < ni; ++i) { - const Face &face = faces[i]; + for (const Face &face : faces) { for (int j = 0; j < 3; ++j) { const int index = (int)(face.n[j] - &nodes[0]); counts[index]++; @@ -278,8 +271,7 @@ void GodotSoftBody3D::update_area() { } void GodotSoftBody3D::reset_link_rest_lengths() { - for (uint32_t i = 0, ni = links.size(); i < ni; ++i) { - Link &link = links[i]; + for (Link &link : links) { link.rl = (link.n[0]->x - link.n[1]->x).length(); link.c1 = link.rl * link.rl; } @@ -287,8 +279,7 @@ void GodotSoftBody3D::reset_link_rest_lengths() { void GodotSoftBody3D::update_link_constants() { real_t inv_linear_stiffness = 1.0 / linear_stiffness; - for (uint32_t i = 0, ni = links.size(); i < ni; ++i) { - Link &link = links[i]; + for (Link &link : links) { link.c0 = (link.n[0]->im + link.n[1]->im) * inv_linear_stiffness; } } @@ -619,9 +610,9 @@ void GodotSoftBody3D::generate_bending_constraints(int p_distance) { } } } - for (i = 0; i < links.size(); ++i) { - const int ia = (int)(links[i].n[0] - &nodes[0]); - const int ib = (int)(links[i].n[1] - &nodes[0]); + for (Link &link : links) { + const int ia = (int)(link.n[0] - &nodes[0]); + const int ib = (int)(link.n[1] - &nodes[0]); int idx = ib * n + ia; int idx_inv = ia * n + ib; adj[idx] = 1; @@ -635,9 +626,9 @@ void GodotSoftBody3D::generate_bending_constraints(int p_distance) { // Build node links. node_links.resize(nodes.size()); - for (i = 0; i < links.size(); ++i) { - const int ia = (int)(links[i].n[0] - &nodes[0]); - const int ib = (int)(links[i].n[1] - &nodes[0]); + for (Link &link : links) { + const int ia = (int)(link.n[0] - &nodes[0]); + const int ib = (int)(link.n[1] - &nodes[0]); if (node_links[ia].find(ib) == -1) { node_links[ia].push_back(ib); } @@ -649,8 +640,7 @@ void GodotSoftBody3D::generate_bending_constraints(int p_distance) { for (uint32_t ii = 0; ii < node_links.size(); ii++) { for (uint32_t jj = 0; jj < node_links[ii].size(); jj++) { int k = node_links[ii][jj]; - for (uint32_t kk = 0; kk < node_links[k].size(); kk++) { - int l = node_links[k][kk]; + for (const int &l : node_links[k]) { if ((int)ii != l) { int idx_ik = k * n + ii; int idx_kj = l * n + k; @@ -916,8 +906,7 @@ void GodotSoftBody3D::set_drag_coefficient(real_t p_val) { } void GodotSoftBody3D::add_velocity(const Vector3 &p_velocity) { - for (uint32_t i = 0, ni = nodes.size(); i < ni; ++i) { - Node &node = nodes[i]; + for (Node &node : nodes) { if (node.im > 0) { node.v += p_velocity; } @@ -929,26 +918,22 @@ void GodotSoftBody3D::apply_forces(const LocalVector<GodotArea3D *> &p_wind_area return; } - uint32_t i, ni; int32_t j; real_t volume = 0.0; const Vector3 &org = nodes[0].x; // Iterate over faces (try not to iterate elsewhere if possible). - for (i = 0, ni = faces.size(); i < ni; ++i) { - const Face &face = faces[i]; - + for (const Face &face : faces) { Vector3 wind_force(0, 0, 0); // Compute volume. volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org)); // Compute nodal forces from area winds. - int wind_area_count = p_wind_areas.size(); - if (wind_area_count > 0) { - for (j = 0; j < wind_area_count; j++) { - wind_force += _compute_area_windforce(p_wind_areas[j], &face); + if (!p_wind_areas.is_empty()) { + for (const GodotArea3D *area : p_wind_areas) { + wind_force += _compute_area_windforce(area, &face); } for (j = 0; j < 3; j++) { @@ -962,8 +947,7 @@ void GodotSoftBody3D::apply_forces(const LocalVector<GodotArea3D *> &p_wind_area // Apply nodal pressure forces. if (pressure_coefficient > CMP_EPSILON) { real_t ivolumetp = 1.0 / Math::abs(volume) * pressure_coefficient; - for (i = 0, ni = nodes.size(); i < ni; ++i) { - Node &node = nodes[i]; + for (Node &node : nodes) { if (node.im > 0) { node.f += node.n * (node.area * ivolumetp); } @@ -1048,9 +1032,7 @@ void GodotSoftBody3D::predict_motion(real_t p_delta) { real_t clamp_delta_v = max_displacement * inv_delta; // Integrate. - uint32_t i, ni; - for (i = 0, ni = nodes.size(); i < ni; ++i) { - Node &node = nodes[i]; + for (Node &node : nodes) { node.q = node.x; Vector3 delta_v = node.f * node.im * p_delta; for (int c = 0; c < 3; c++) { @@ -1065,9 +1047,7 @@ void GodotSoftBody3D::predict_motion(real_t p_delta) { update_bounds(); // Node tree update. - for (i = 0, ni = nodes.size(); i < ni; ++i) { - const Node &node = nodes[i]; - + for (const Node &node : nodes) { AABB node_aabb(node.x, Vector3()); node_aabb.expand_to(node.x + node.v * p_delta); node_aabb.grow_by(collision_margin); @@ -1088,17 +1068,13 @@ void GodotSoftBody3D::predict_motion(real_t p_delta) { void GodotSoftBody3D::solve_constraints(real_t p_delta) { const real_t inv_delta = 1.0 / p_delta; - uint32_t i, ni; - - for (i = 0, ni = links.size(); i < ni; ++i) { - Link &link = links[i]; + for (Link &link : links) { link.c3 = link.n[1]->q - link.n[0]->q; link.c2 = 1 / (link.c3.length_squared() * link.c0); } // Solve velocities. - for (i = 0, ni = nodes.size(); i < ni; ++i) { - Node &node = nodes[i]; + for (Node &node : nodes) { node.x = node.q + node.v * p_delta; } @@ -1108,9 +1084,7 @@ void GodotSoftBody3D::solve_constraints(real_t p_delta) { solve_links(1.0, ti); } const real_t vc = (1.0 - damping_coefficient) * inv_delta; - for (i = 0, ni = nodes.size(); i < ni; ++i) { - Node &node = nodes[i]; - + for (Node &node : nodes) { node.x += node.bv * p_delta; node.bv = Vector3(); @@ -1123,8 +1097,7 @@ void GodotSoftBody3D::solve_constraints(real_t p_delta) { } void GodotSoftBody3D::solve_links(real_t kst, real_t ti) { - for (uint32_t i = 0, ni = links.size(); i < ni; ++i) { - Link &link = links[i]; + for (Link &link : links) { if (link.c0 > 0) { Node &node_a = *link.n[0]; Node &node_b = *link.n[1]; @@ -1183,9 +1156,7 @@ void GodotSoftBody3D::query_ray(const Vector3 &p_from, const Vector3 &p_to, Godo void GodotSoftBody3D::initialize_face_tree() { face_tree.clear(); - for (uint32_t i = 0; i < faces.size(); ++i) { - Face &face = faces[i]; - + for (Face &face : faces) { AABB face_aabb; face_aabb.position = face.n[0]->x; @@ -1199,9 +1170,7 @@ void GodotSoftBody3D::initialize_face_tree() { } void GodotSoftBody3D::update_face_tree(real_t p_delta) { - for (uint32_t i = 0; i < faces.size(); ++i) { - const Face &face = faces[i]; - + for (const Face &face : faces) { AABB face_aabb; const Node *node0 = face.n[0]; diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index c3aad22932..93572965d2 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -445,7 +445,7 @@ struct _RestCallbackData { _RestResultData *other_results = nullptr; }; -static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { _RestCallbackData *rd = static_cast<_RestCallbackData *>(p_userdata); Vector3 contact_rel = p_point_B - p_point_A; @@ -480,7 +480,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect // Keep this result as separate result. result.len = len; result.contact = p_point_B; - result.normal = contact_rel / len; + result.normal = normal; result.object = rd->object; result.shape = rd->shape; result.local_shape = rd->local_shape; @@ -499,7 +499,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect rd->best_result.len = len; rd->best_result.contact = p_point_B; - rd->best_result.normal = contact_rel / len; + rd->best_result.normal = normal; rd->best_result.object = rd->object; rd->best_result.shape = rd->shape; rd->best_result.local_shape = rd->local_shape; diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 62e1eb326d..fd36e7ac10 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -154,6 +154,7 @@ public: virtual RID decal_instance_create(RID p_decal) override { return RID(); } virtual void decal_instance_free(RID p_decal_instance) override {} virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {} + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {} /* RENDER TARGET */ diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 55f88d9bf1..b9e3c4f303 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -769,6 +769,49 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, } } +static Vector2 compute_polyline_segment_dir(const Vector<Point2> &p_points, int p_index, const Vector2 &p_prev_segment_dir) { + int point_count = p_points.size(); + + bool is_last_point = (p_index == point_count - 1); + + Vector2 segment_dir; + + if (is_last_point) { + segment_dir = p_prev_segment_dir; + } else { + segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized(); + + if (segment_dir.is_zero_approx()) { + segment_dir = p_prev_segment_dir; + } + } + + return segment_dir; +} + +static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) { + Vector2 bisector; + float length = 1.0f; + + bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized(); + + float angle = atan2f(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir)); + float sin_angle = sinf(angle); + + if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) { + length = 1.0f / sin_angle; + length = CLAMP(length, -3.0f, 3.0f); + } else { + bisector = p_segment_dir.orthogonal(); + } + + if (bisector.is_zero_approx()) { + bisector = p_segment_dir.orthogonal(); + } + + return bisector * length; +} + void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.get_or_null(p_item); @@ -777,20 +820,68 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Color color = Color(1, 1, 1, 1); Vector<int> indices; - int pc = p_points.size(); - int pc2 = pc * 2; - - Vector2 prev_t; - int j2; + int point_count = p_points.size(); Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!pline); + if (p_width < 0) { + if (p_antialiased) { + WARN_PRINT("Antialiasing is not supported for thin polylines drawn using line strips (`p_width < 0`)."); + } + + pline->primitive = RS::PRIMITIVE_LINE_STRIP; + + if (p_colors.size() == 1 || p_colors.size() == point_count) { + pline->polygon.create(indices, p_points, p_colors); + } else { + Vector<Color> colors; + if (p_colors.is_empty()) { + colors.push_back(color); + } else { + colors.resize(point_count); + Color *colors_ptr = colors.ptrw(); + for (int i = 0; i < point_count; i++) { + if (i < p_colors.size()) { + color = p_colors[i]; + } + colors_ptr[i] = color; + } + } + pline->polygon.create(indices, p_points, colors); + } + return; + } + + int polyline_point_count = point_count * 2; + + bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]); + Vector2 first_segment_dir; + Vector2 last_segment_dir; + + // Search for first non-zero vector between two segments. + for (int i = 1; i < point_count; i++) { + first_segment_dir = (p_points[i] - p_points[i - 1]).normalized(); + + if (!first_segment_dir.is_zero_approx()) { + break; + } + } + + // Search for last non-zero vector between two segments. + for (int i = point_count - 1; i >= 1; i--) { + last_segment_dir = (p_points[i] - p_points[i - 1]).normalized(); + + if (!last_segment_dir.is_zero_approx()) { + break; + } + } + PackedColorArray colors; PackedVector2Array points; - colors.resize(pc2); - points.resize(pc2); + colors.resize(polyline_point_count); + points.resize(polyline_point_count); Vector2 *points_ptr = points.ptrw(); Color *colors_ptr = colors.ptrw(); @@ -845,14 +936,14 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point PackedColorArray colors_left; PackedVector2Array points_left; - colors_left.resize(pc2); - points_left.resize(pc2); + colors_left.resize(polyline_point_count); + points_left.resize(polyline_point_count); PackedColorArray colors_right; PackedVector2Array points_right; - colors_right.resize(pc2); - points_right.resize(pc2); + colors_right.resize(polyline_point_count); + points_right.resize(polyline_point_count); Item::CommandPolygon *pline_begin = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!pline_begin); @@ -898,79 +989,81 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Color *colors_left_ptr = colors_left.ptrw(); Color *colors_right_ptr = colors_right.ptrw(); - for (int i = 0, j = 0; i < pc; i++, j += 2) { - bool is_begin = i == 0; - bool is_end = i == pc - 1; + Vector2 prev_segment_dir; + for (int i = 0; i < point_count; i++) { + bool is_first_point = (i == 0); + bool is_last_point = (i == point_count - 1); - Vector2 t; - Vector2 end_border; - Vector2 begin_border; - if (is_end) { - t = prev_t; - end_border = (p_points[i] - p_points[i - 1]).normalized() * border_size; - } else { - t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); - if (is_begin) { - prev_t = t; - begin_border = (p_points[i] - p_points[i + 1]).normalized() * border_size; - } + Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir); + if (is_first_point && loop) { + prev_segment_dir = last_segment_dir; + } else if (is_last_point && loop) { + prev_segment_dir = first_segment_dir; } - j2 = j + 1; + Vector2 base_edge_offset; + if (is_first_point && !loop) { + base_edge_offset = first_segment_dir.orthogonal(); + } else if (is_last_point && !loop) { + base_edge_offset = last_segment_dir.orthogonal(); + } else { + base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir); + } - Vector2 dir = (t + prev_t).normalized(); - Vector2 tangent = dir * p_width * 0.5; - Vector2 border = dir * border_size; + Vector2 edge_offset = base_edge_offset * (p_width * 0.5f); + Vector2 border = base_edge_offset * border_size; Vector2 pos = p_points[i]; - points_ptr[j] = pos + tangent; - points_ptr[j2] = pos - tangent; + points_ptr[i * 2 + 0] = pos + edge_offset; + points_ptr[i * 2 + 1] = pos - edge_offset; - points_left_ptr[j] = pos + tangent + border; - points_left_ptr[j2] = pos + tangent; + points_left_ptr[i * 2 + 0] = pos + edge_offset + border; + points_left_ptr[i * 2 + 1] = pos + edge_offset; - points_right_ptr[j] = pos - tangent; - points_right_ptr[j2] = pos - tangent - border; + points_right_ptr[i * 2 + 0] = pos - edge_offset; + points_right_ptr[i * 2 + 1] = pos - edge_offset - border; if (i < p_colors.size()) { color = p_colors[i]; color2 = Color(color.r, color.g, color.b, 0); } - colors_ptr[j] = color; - colors_ptr[j2] = color; + colors_ptr[i * 2 + 0] = color; + colors_ptr[i * 2 + 1] = color; + + colors_left_ptr[i * 2 + 0] = color2; + colors_left_ptr[i * 2 + 1] = color; - colors_left_ptr[j] = color2; - colors_left_ptr[j2] = color; + colors_right_ptr[i * 2 + 0] = color; + colors_right_ptr[i * 2 + 1] = color2; - colors_right_ptr[j] = color; - colors_right_ptr[j2] = color2; + if (is_first_point) { + Vector2 begin_border = loop ? Vector2() : -segment_dir * border_size; - if (is_begin) { - points_begin_ptr[0] = pos + tangent + begin_border; - points_begin_ptr[1] = pos - tangent + begin_border; - points_begin_ptr[2] = pos + tangent; - points_begin_ptr[3] = pos - tangent; + points_begin_ptr[0] = pos + edge_offset + begin_border; + points_begin_ptr[1] = pos - edge_offset + begin_border; + points_begin_ptr[2] = pos + edge_offset; + points_begin_ptr[3] = pos - edge_offset; colors_begin_ptr[0] = color2; colors_begin_ptr[1] = color2; colors_begin_ptr[2] = color; colors_begin_ptr[3] = color; - points_begin_left_corner_ptr[0] = pos - tangent - border; - points_begin_left_corner_ptr[1] = pos - tangent + begin_border - border; - points_begin_left_corner_ptr[2] = pos - tangent; - points_begin_left_corner_ptr[3] = pos - tangent + begin_border; + points_begin_left_corner_ptr[0] = pos - edge_offset - border; + points_begin_left_corner_ptr[1] = pos - edge_offset + begin_border - border; + points_begin_left_corner_ptr[2] = pos - edge_offset; + points_begin_left_corner_ptr[3] = pos - edge_offset + begin_border; colors_begin_left_corner_ptr[0] = color2; colors_begin_left_corner_ptr[1] = color2; colors_begin_left_corner_ptr[2] = color; colors_begin_left_corner_ptr[3] = color2; - points_begin_right_corner_ptr[0] = pos + tangent + begin_border; - points_begin_right_corner_ptr[1] = pos + tangent + begin_border + border; - points_begin_right_corner_ptr[2] = pos + tangent; - points_begin_right_corner_ptr[3] = pos + tangent + border; + points_begin_right_corner_ptr[0] = pos + edge_offset + begin_border; + points_begin_right_corner_ptr[1] = pos + edge_offset + begin_border + border; + points_begin_right_corner_ptr[2] = pos + edge_offset; + points_begin_right_corner_ptr[3] = pos + edge_offset + border; colors_begin_right_corner_ptr[0] = color2; colors_begin_right_corner_ptr[1] = color2; @@ -978,31 +1071,33 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point colors_begin_right_corner_ptr[3] = color2; } - if (is_end) { - points_end_ptr[0] = pos + tangent + end_border; - points_end_ptr[1] = pos - tangent + end_border; - points_end_ptr[2] = pos + tangent; - points_end_ptr[3] = pos - tangent; + if (is_last_point) { + Vector2 end_border = loop ? Vector2() : prev_segment_dir * border_size; + + points_end_ptr[0] = pos + edge_offset + end_border; + points_end_ptr[1] = pos - edge_offset + end_border; + points_end_ptr[2] = pos + edge_offset; + points_end_ptr[3] = pos - edge_offset; colors_end_ptr[0] = color2; colors_end_ptr[1] = color2; colors_end_ptr[2] = color; colors_end_ptr[3] = color; - points_end_left_corner_ptr[0] = pos - tangent - border; - points_end_left_corner_ptr[1] = pos - tangent + end_border - border; - points_end_left_corner_ptr[2] = pos - tangent; - points_end_left_corner_ptr[3] = pos - tangent + end_border; + points_end_left_corner_ptr[0] = pos - edge_offset - border; + points_end_left_corner_ptr[1] = pos - edge_offset + end_border - border; + points_end_left_corner_ptr[2] = pos - edge_offset; + points_end_left_corner_ptr[3] = pos - edge_offset + end_border; colors_end_left_corner_ptr[0] = color2; colors_end_left_corner_ptr[1] = color2; colors_end_left_corner_ptr[2] = color; colors_end_left_corner_ptr[3] = color2; - points_end_right_corner_ptr[0] = pos + tangent + end_border; - points_end_right_corner_ptr[1] = pos + tangent + end_border + border; - points_end_right_corner_ptr[2] = pos + tangent; - points_end_right_corner_ptr[3] = pos + tangent + border; + points_end_right_corner_ptr[0] = pos + edge_offset + end_border; + points_end_right_corner_ptr[1] = pos + edge_offset + end_border + border; + points_end_right_corner_ptr[2] = pos + edge_offset; + points_end_right_corner_ptr[3] = pos + edge_offset + border; colors_end_right_corner_ptr[0] = color2; colors_end_right_corner_ptr[1] = color2; @@ -1010,7 +1105,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point colors_end_right_corner_ptr[3] = color2; } - prev_t = t; + prev_segment_dir = segment_dir; } pline_begin->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; @@ -1039,33 +1134,41 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point } else { // Makes a single triangle strip for drawing the line. - for (int i = 0, j = 0; i < pc; i++, j += 2) { - Vector2 t; - if (i == pc - 1) { - t = prev_t; - } else { - t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); - if (i == 0) { - prev_t = t; - } + Vector2 prev_segment_dir; + for (int i = 0; i < point_count; i++) { + bool is_first_point = (i == 0); + bool is_last_point = (i == point_count - 1); + + Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir); + if (is_first_point && loop) { + prev_segment_dir = last_segment_dir; + } else if (is_last_point && loop) { + prev_segment_dir = first_segment_dir; } - j2 = j + 1; + Vector2 base_edge_offset; + if (is_first_point && !loop) { + base_edge_offset = first_segment_dir.orthogonal(); + } else if (is_last_point && !loop) { + base_edge_offset = last_segment_dir.orthogonal(); + } else { + base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir); + } - Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 edge_offset = base_edge_offset * (p_width * 0.5f); Vector2 pos = p_points[i]; - points_ptr[j] = pos + tangent; - points_ptr[j2] = pos - tangent; + points_ptr[i * 2 + 0] = pos + edge_offset; + points_ptr[i * 2 + 1] = pos - edge_offset; if (i < p_colors.size()) { color = p_colors[i]; } - colors_ptr[j] = color; - colors_ptr[j2] = color; + colors_ptr[i * 2 + 0] = color; + colors_ptr[i * 2 + 1] = color; - prev_t = t; + prev_segment_dir = segment_dir; } } @@ -1133,20 +1236,23 @@ void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, static const int circle_points = 64; points.resize(circle_points); + Vector2 *points_ptr = points.ptrw(); const real_t circle_point_step = Math_TAU / circle_points; for (int i = 0; i < circle_points; i++) { float angle = i * circle_point_step; - points.write[i].x = Math::cos(angle) * p_radius; - points.write[i].y = Math::sin(angle) * p_radius; - points.write[i] += p_pos; + points_ptr[i].x = Math::cos(angle) * p_radius; + points_ptr[i].y = Math::sin(angle) * p_radius; + points_ptr[i] += p_pos; } + indices.resize((circle_points - 2) * 3); + int *indices_ptr = indices.ptrw(); for (int i = 0; i < circle_points - 2; i++) { - indices.write[i * 3 + 0] = 0; - indices.write[i * 3 + 1] = i + 1; - indices.write[i * 3 + 2] = i + 2; + indices_ptr[i * 3 + 0] = 0; + indices_ptr[i * 3 + 1] = i + 1; + indices_ptr[i * 3 + 2] = i + 2; } Vector<Color> color; diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 2494ddf631..1106fc4f1e 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -222,7 +222,7 @@ public: void canvas_item_set_update_when_visible(RID p_item, bool p_update); void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false); - void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); + void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false); void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index a52716cd78..08133bf8d6 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -540,9 +540,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re occlusion_texture = RD::get_singleton()->texture_create_shared(tv, occlusion_data); } - for (uint32_t i = 0; i < cascades.size(); i++) { - SDFGI::Cascade &cascade = cascades[i]; - + for (SDFGI::Cascade &cascade : cascades) { /* 3D Textures */ cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView()); @@ -743,9 +741,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re } //direct light - for (uint32_t i = 0; i < cascades.size(); i++) { - SDFGI::Cascade &cascade = cascades[i]; - + for (SDFGI::Cascade &cascade : cascades) { Vector<RD::Uniform> uniforms; { RD::Uniform u; @@ -1134,8 +1130,7 @@ void GI::SDFGI::free_data() { } GI::SDFGI::~SDFGI() { - for (uint32_t i = 0; i < cascades.size(); i++) { - const SDFGI::Cascade &c = cascades[i]; + for (const SDFGI::Cascade &c : cascades) { RD::get_singleton()->free(c.light_data); RD::get_singleton()->free(c.light_aniso_0_tex); RD::get_singleton()->free(c.light_aniso_1_tex); @@ -1198,8 +1193,7 @@ void GI::SDFGI::update(RID p_env, const Vector3 &p_world_position) { int32_t drag_margin = (cascade_size / SDFGI::PROBE_DIVISOR) / 2; - for (uint32_t i = 0; i < cascades.size(); i++) { - SDFGI::Cascade &cascade = cascades[i]; + for (SDFGI::Cascade &cascade : cascades) { cascade.dirty_regions = Vector3i(); Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(cascade_size / SDFGI::PROBE_DIVISOR) * 0.5; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 863e8d6c15..7e02f98ce9 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -1085,8 +1085,8 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con sky->reflection.dirty = true; } + sky_scene_state.ubo.directional_light_count = 0; if (shader_data->uses_light) { - sky_scene_state.ubo.directional_light_count = 0; // Run through the list of lights in the scene and pick out the Directional Lights. // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called // after the depth prepass, but this runs before the depth prepass diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 93c741fd34..ad63d3fd4b 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1365,8 +1365,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } //cube shadows are rendered in their own way - for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + for (const int &index : p_render_data->cube_shadows) { + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); } if (p_render_data->directional_shadows.size()) { @@ -1480,7 +1480,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); p_render_data->directional_light_count = directional_light_count; @@ -2415,8 +2415,7 @@ void RenderForwardClustered::_render_shadow_process() { void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) { RD::get_singleton()->draw_command_begin_label("Shadow Render"); - for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { - SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); } @@ -3376,9 +3375,7 @@ int RenderForwardClustered::sdfgi_get_pending_region_count(const Ref<RenderScene Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); int dirty_count = 0; - for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) { - const RendererRD::GI::SDFGI::Cascade &c = sdfgi->cascades[i]; - + for (const RendererRD::GI::SDFGI::Cascade &c : sdfgi->cascades) { if (c.dirty_regions == RendererRD::GI::SDFGI::Cascade::DIRTY_ALL) { dirty_count++; } else { @@ -4007,11 +4004,11 @@ RenderForwardClustered::~RenderForwardClustered() { RSG::light_storage->directional_shadow_atlas_set_size(0); { - for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { - RD::get_singleton()->free(scene_state.uniform_buffers[i]); + for (const RID &rid : scene_state.uniform_buffers) { + RD::get_singleton()->free(rid); } - for (uint32_t i = 0; i < scene_state.implementation_uniform_buffers.size(); i++) { - RD::get_singleton()->free(scene_state.implementation_uniform_buffers[i]); + for (const RID &rid : scene_state.implementation_uniform_buffers) { + RD::get_singleton()->free(rid); } RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 7eabce2f79..412406c0b4 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -44,7 +44,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { valid = false; ubo_size = 0; uniforms.clear(); - uses_screen_texture = false; if (code.is_empty()) { return; //just invalid, but no error @@ -73,9 +72,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_position = false; uses_sss = false; uses_transmittance = false; - uses_screen_texture = false; - uses_depth_texture = false; - uses_normal_texture = false; uses_time = false; writes_modelview_or_projection = false; uses_world_coordinates = false; @@ -120,9 +116,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; - actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_ROUGHNESS_TEXTURE"] = &uses_normal_texture; actions.usage_flag_pointers["DISCARD"] = &uses_discard; actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; @@ -151,6 +144,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { depth_test = DepthTest(depth_testi); cull_mode = Cull(cull_modei); uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps; + uses_screen_texture = gen_code.uses_screen_texture; + uses_depth_texture = gen_code.uses_depth_texture; + uses_normal_texture = gen_code.uses_normal_roughness_texture; uses_vertex_time = gen_code.uses_vertex_time; uses_fragment_time = gen_code.uses_fragment_time; @@ -607,9 +603,6 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.renames["POINT_COORD"] = "gl_PointCoord"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "color_buffer"; - actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; actions.renames["DEPTH"] = "gl_FragDepth"; actions.renames["OUTPUT_IS_SRGB"] = "true"; actions.renames["FOG"] = "fog"; @@ -674,7 +667,6 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; @@ -707,10 +699,6 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps - actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]"; - actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter - actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 816248567b..25204f1abf 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -579,8 +579,8 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { } //cube shadows are rendered in their own way - for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + for (const int &index : p_render_data->cube_shadows) { + _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); } if (p_render_data->directional_shadows.size()) { @@ -632,7 +632,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); p_render_data->directional_light_count = directional_light_count; } @@ -1340,8 +1340,7 @@ void RenderForwardMobile::_render_shadow_process() { void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) { RD::get_singleton()->draw_command_begin_label("Shadow Render"); - for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { - SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); } @@ -2810,8 +2809,8 @@ RenderForwardMobile::~RenderForwardMobile() { } { - for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { - RD::get_singleton()->free(scene_state.uniform_buffers[i]); + for (const RID &rid : scene_state.uniform_buffers) { + RD::get_singleton()->free(rid); } RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index ee4c8001eb..3d1d78c63d 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -46,7 +46,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { valid = false; ubo_size = 0; uniforms.clear(); - uses_screen_texture = false; if (code.is_empty()) { return; //just invalid, but no error @@ -74,9 +73,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_vertex = false; uses_sss = false; uses_transmittance = false; - uses_screen_texture = false; - uses_depth_texture = false; - uses_normal_texture = false; uses_time = false; writes_modelview_or_projection = false; uses_world_coordinates = false; @@ -121,9 +117,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { // actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; // actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; - actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_ROUGHNESS_TEXTURE"] = &uses_normal_texture; actions.usage_flag_pointers["DISCARD"] = &uses_discard; actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; @@ -152,6 +145,10 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { depth_test = DepthTest(depth_testi); uses_vertex_time = gen_code.uses_vertex_time; uses_fragment_time = gen_code.uses_fragment_time; + uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps; + uses_screen_texture = gen_code.uses_screen_texture; + uses_depth_texture = gen_code.uses_depth_texture; + uses_normal_texture = gen_code.uses_normal_roughness_texture; #if 0 print_line("**compiling shader:"); @@ -498,9 +495,6 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.renames["POINT_COORD"] = "gl_PointCoord"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "color_buffer"; - actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; actions.renames["DEPTH"] = "gl_FragDepth"; actions.renames["OUTPUT_IS_SRGB"] = "true"; actions.renames["FOG"] = "fog"; @@ -565,7 +559,6 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 1f92697ecc..6f1f00cedc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -128,6 +128,7 @@ public: bool uses_screen_texture = false; bool uses_depth_texture = false; bool uses_normal_texture = false; + bool uses_screen_texture_mipmaps = false; bool uses_time = false; bool uses_vertex_time = false; bool uses_fragment_time = false; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 0c6dcb553a..638fe44266 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -455,7 +455,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend light_count++; - if (light_count == MAX_LIGHTS_PER_ITEM) { + if (light_count == MAX_LIGHTS_PER_ITEM - 1) { break; } } @@ -525,10 +525,12 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend if (rect->flags & CANVAS_RECT_FLIP_H) { src_rect.size.x *= -1; + push_constant.flags |= FLAGS_FLIP_H; } if (rect->flags & CANVAS_RECT_FLIP_V) { src_rect.size.y *= -1; + push_constant.flags |= FLAGS_FLIP_V; } if (rect->flags & CANVAS_RECT_TRANSPOSE) { @@ -2034,7 +2036,6 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA); actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED); - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; actions.usage_flag_pointers["TIME"] = &uses_time; @@ -2046,6 +2047,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps; + uses_screen_texture = gen_code.uses_screen_texture; if (version.is_null()) { version = canvas_singleton->shader.canvas_shader.version_create(); @@ -2423,7 +2425,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture"; actions.renames["SPECULAR_SHININESS"] = "specular_shininess"; actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "screen_texture"; actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size"; actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["POINT_COORD"] = "gl_PointCoord"; @@ -2444,7 +2445,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; @@ -2459,7 +2459,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { actions.custom_samplers["TEXTURE"] = "texture_sampler"; actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler"; actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler"; - actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture actions.sampler_array_name = "material_samplers"; actions.base_texture_binding_index = 1; actions.texture_layout_set = MATERIAL_UNIFORM_SET; @@ -2632,8 +2631,10 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { shader_type canvas_item; +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + void fragment() { - vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0); + vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0); if (c.a > 0.0001) { c.rgb /= c.a; @@ -2657,8 +2658,10 @@ void fragment() { shader_type canvas_item; +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + void fragment() { - vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0); + vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0); COLOR.rgb = c.rgb; } )"); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 266083fc49..7dea4a1a65 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -86,6 +86,9 @@ class RendererCanvasRenderRD : public RendererCanvasRender { FLAGS_USE_MSDF = (1 << 28), FLAGS_USE_LCD = (1 << 29), + + FLAGS_FLIP_H = (1 << 30), + FLAGS_FLIP_V = (1 << 31), }; enum { diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 2d5263a3e2..533a912a34 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -165,8 +165,7 @@ void ShaderRD::_clear_version(Version *p_version) { } void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template) { - for (uint32_t i = 0; i < p_template.chunks.size(); i++) { - const StageTemplate::Chunk &chunk = p_template.chunks[i]; + for (const StageTemplate::Chunk &chunk : p_template.chunks) { switch (chunk.type) { case StageTemplate::Chunk::TYPE_VERSION_DEFINES: { builder.append("\n"); //make sure defines begin at newline diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index eb5f68849e..1fb8b28b15 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -502,6 +502,12 @@ void main() { if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); + if (bool(draw_data.flags & FLAGS_FLIP_H)) { + normal.x = -normal.x; + } + if (bool(draw_data.flags & FLAGS_FLIP_V)) { + normal.y = -normal.y; + } normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; } else { diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 1b627a3e81..a904f4e0a6 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -27,6 +27,9 @@ #define FLAGS_USE_MSDF (1 << 28) #define FLAGS_USE_LCD (1 << 29) +#define FLAGS_FLIP_H (1 << 30) +#define FLAGS_FLIP_V (1 << 31) + #define SAMPLER_NEAREST_CLAMP 0 #define SAMPLER_LINEAR_CLAMP 1 #define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 @@ -134,7 +137,7 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture; layout(set = 0, binding = 5) uniform sampler shadow_sampler; -layout(set = 0, binding = 6) uniform texture2D screen_texture; +layout(set = 0, binding = 6) uniform texture2D color_buffer; layout(set = 0, binding = 7) uniform texture2D sdf_texture; layout(set = 0, binding = 8) uniform sampler material_samplers[12]; diff --git a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl index 134aae5ce7..b1ff46dd3b 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl @@ -56,7 +56,7 @@ vec4 screen_space_to_view_space_depth(vec4 p_depth) { float depth_linearize_mul = params.z_near; float depth_linearize_add = params.z_far; - // Optimised version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar" + // Optimized version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar" // Set your depth_linearize_mul and depth_linearize_add to: // depth_linearize_mul = ( cameraClipFar * cameraClipNear) / ( cameraClipFar - cameraClipNear ); diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl index 2a87e273bc..ffaa6872c9 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl @@ -221,7 +221,7 @@ void SSAOTap(const int p_quality_level, inout float r_obscurance_sum, inout floa // snap to pixel center (more correct obscurance math, avoids artifacts) sample_offset = round(sample_offset); - // calculate MIP based on the sample distance from the centre, similar to as described + // calculate MIP based on the sample distance from the center, similar to as described // in http://graphics.cs.williams.edu/papers/SAOHPG12/. float mip_level = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset); @@ -259,7 +259,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o // get this pixel's viewspace depth pix_z = valuesUL.y; - // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0) + // get left right top bottom neighboring pixels for edge detection (gets compiled out on quality_level == 0) pix_left_z = valuesUL.x; pix_top_z = valuesUL.z; pix_right_z = valuesBR.z; @@ -304,7 +304,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o float obscurance_sum = 0.0; float weight_sum = 0.0; - // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + // edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats @@ -318,7 +318,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o if (!p_adaptive_base && (p_quality_level >= SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET)) { // disable in case of quality level 4 (reference) if (p_quality_level != 4) { - //approximate neighbouring pixels positions (actually just deltas or "positions - pix_center_pos" ) + //approximate neighboring pixels positions (actually just deltas or "positions - pix_center_pos" ) vec3 normalized_viewspace_dir = vec3(pix_center_pos.xy / pix_center_pos.zz, 1.0); vec3 pixel_left_delta = vec3(-pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_left_z - pix_center_pos.z); vec3 pixel_right_delta = vec3(+pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_right_z - pix_center_pos.z); diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl index 04f98964e8..d234ab4417 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl @@ -80,7 +80,7 @@ void main() { #ifdef PROCESS_MAPA vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; - float centre = textureLod(source_importance, uv, 0.0).x; + float center = textureLod(source_importance, uv, 0.0).x; vec2 half_pixel = params.half_screen_pixel_size; @@ -98,7 +98,7 @@ void main() { #ifdef PROCESS_MAPB vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; - float centre = textureLod(source_importance, uv, 0.0).x; + float center = textureLod(source_importance, uv, 0.0).x; vec2 half_pixel = params.half_screen_pixel_size; diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl index f6a9a92fac..45cc62d361 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl @@ -60,8 +60,8 @@ void main() { int mx = int(pix_pos.x % 2); int my = int(pix_pos.y % 2); int index_center = mx + my * 2; // center index - int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal - int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical + int index_horizontal = (1 - mx) + my * 2; // neighboring, horizontal + int index_vertical = mx + (1 - my) * 2; // neighboring, vertical int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal vec2 center_val = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0).xy; diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl index 513791dfbf..de7b97953f 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl @@ -234,7 +234,7 @@ void SSILTap(const int p_quality_level, inout vec3 r_color_sum, inout float r_ob // snap to pixel center (more correct obscurance math, avoids artifacts) sample_offset = round(sample_offset); - // calculate MIP based on the sample distance from the centre, similar to as described + // calculate MIP based on the sample distance from the center, similar to as described // in http://graphics.cs.williams.edu/papers/SAOHPG12/. float mip_level = (p_quality_level < SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset); @@ -272,7 +272,7 @@ void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, o // get this pixel's viewspace depth pix_z = valuesUL.y; - // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0) + // get left right top bottom neighboring pixels for edge detection (gets compiled out on quality_level == 0) pix_left_z = valuesUL.x; pix_top_z = valuesUL.z; pix_right_z = valuesBR.z; @@ -318,7 +318,7 @@ void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, o float obscurance_sum = 0.0; float weight_sum = 0.0; - // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + // edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl index 47c56571f6..f48e6c4341 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl @@ -124,14 +124,14 @@ void main() { vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; - vec4 centre = textureLod(source_ssil, uv, 0.0); + vec4 center = textureLod(source_ssil, uv, 0.0); vec4 value = textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x * 3, -half_pixel.y)), 0.0) * 0.2; value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x, -half_pixel.y * 3)), 0.0) * 0.2; value += textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x, +half_pixel.y * 3)), 0.0) * 0.2; value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x * 3, +half_pixel.y)), 0.0) * 0.2; - vec4 sampled = value + centre * 0.2; + vec4 sampled = value + center * 0.2; #else #ifdef MODE_SMART diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl index 6b6b02739d..193e3458ab 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl @@ -82,7 +82,7 @@ void main() { #ifdef PROCESS_MAPA vec2 uv = (vec2(ssC) + 0.5) * params.half_screen_pixel_size * 2.0; - float centre = textureLod(source_importance, uv, 0.0).x; + float center = textureLod(source_importance, uv, 0.0).x; vec2 half_pixel = params.half_screen_pixel_size; @@ -100,7 +100,7 @@ void main() { #ifdef PROCESS_MAPB vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; - float centre = textureLod(source_importance, uv, 0.0).x; + float center = textureLod(source_importance, uv, 0.0).x; vec2 half_pixel = params.half_screen_pixel_size; diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl index 9e86ac0cf0..ed85b8ee4c 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl @@ -62,8 +62,8 @@ void main() { int mx = int(pix_pos.x % 2); int my = int(pix_pos.y % 2); int index_center = mx + my * 2; // center index - int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal - int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical + int index_horizontal = (1 - mx) + my * 2; // neighboring, horizontal + int index_vertical = mx + (1 - my) * 2; // neighboring, vertical int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal vec4 color = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0); diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl index 9f7449b8aa..06709f65d3 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl @@ -24,7 +24,7 @@ struct ProcessVoxel { uint albedo; // rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors. uint light; // rgbe8985 encoded total saved light, extra 2 bits for neighbors. uint light_aniso; // 55555 light anisotropy, extra 2 bits for neighbors. - //total neighbours: 26 + //total neighbors: 26 }; #ifdef MODE_PROCESS_STATIC @@ -443,10 +443,10 @@ void main() { imageStore(dst_aniso1, positioni, vec4(aniso1, 0.0, 0.0)); imageStore(dst_light, positioni, uvec4(light_total_rgbe)); - //also fill neighbours, so light interpolation during the indirect pass works + //also fill neighbors, so light interpolation during the indirect pass works - //recover the neighbour list from the leftover bits - uint neighbours = (voxel_albedo >> 21) | ((voxel_position >> 21) << 11) | ((process_voxels.data[voxel_index].light >> 30) << 22) | ((process_voxels.data[voxel_index].light_aniso >> 30) << 24); + //recover the neighbor list from the leftover bits + uint neighbors = (voxel_albedo >> 21) | ((voxel_position >> 21) << 11) | ((process_voxels.data[voxel_index].light >> 30) << 22) | ((process_voxels.data[voxel_index].light_aniso >> 30) << 24); const uint max_neighbours = 26; const ivec3 neighbour_positions[max_neighbours] = ivec3[]( @@ -478,7 +478,7 @@ void main() { ivec3(1, 1, 1)); for (uint i = 0; i < max_neighbours; i++) { - if (bool(neighbours & (1 << i))) { + if (bool(neighbors & (1 << i))) { ivec3 neighbour_pos = positioni + neighbour_positions[i]; imageStore(dst_light, neighbour_pos, uvec4(light_total_rgbe)); imageStore(dst_aniso0, neighbour_pos, aniso0); diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl index bce98f4054..dd35ae3b73 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl @@ -102,10 +102,10 @@ dispatch_data; struct ProcessVoxel { uint position; // xyz 7 bit packed, extra 11 bits for neighbors. - uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours - uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours - //total neighbours: 26 + uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbors + uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbors + //total neighbors: 26 }; layout(set = 0, binding = 11, std430) restrict buffer writeonly ProcessVoxels { @@ -135,10 +135,10 @@ dispatch_data; struct ProcessVoxel { uint position; // xyz 7 bit packed, extra 11 bits for neighbors. - uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours - uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours - //total neighbours: 26 + uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbors + uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbors + //total neighbors: 26 }; layout(set = 0, binding = 6, std430) restrict buffer readonly ProcessVoxels { @@ -1016,14 +1016,14 @@ void main() { store_positions[index].albedo = rgb >> 1; //store as it comes (555) to avoid precision loss (and move away the alpha bit) store_positions[index].albedo |= (facing & 0x3F) << 15; // store facing in bits 15-21 - store_positions[index].albedo |= neighbour_bits << 21; //store lower 11 bits of neighbours with remaining albedo - store_positions[index].position |= (neighbour_bits >> 11) << 21; //store 11 bits more of neighbours with position + store_positions[index].albedo |= neighbour_bits << 21; //store lower 11 bits of neighbors with remaining albedo + store_positions[index].position |= (neighbour_bits >> 11) << 21; //store 11 bits more of neighbors with position store_positions[index].light = imageLoad(src_light, pos).r; store_positions[index].light_aniso = imageLoad(src_light_aniso, pos).r; - //add neighbours - store_positions[index].light |= (neighbour_bits >> 22) << 30; //store 2 bits more of neighbours with light - store_positions[index].light_aniso |= (neighbour_bits >> 24) << 30; //store 2 bits more of neighbours with aniso + //add neighbors + store_positions[index].light |= (neighbour_bits >> 22) << 30; //store 2 bits more of neighbors with light + store_positions[index].light_aniso |= (neighbour_bits >> 24) << 30; //store 2 bits more of neighbors with aniso } groupMemoryBarrier(); diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index d32e6d717f..51e503b5b3 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -1351,8 +1351,8 @@ void fragment_shader(in SceneData scene_data) { #endif // USE_MULTIVIEW for (int i = 0; i < 4; i++) { - const vec2 neighbours[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); - vec2 neighbour_coord = base_coord + neighbours[i] * scene_data.screen_pixel_size; + const vec2 neighbors[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); + vec2 neighbour_coord = base_coord + neighbors[i] * scene_data.screen_pixel_size; #ifdef USE_MULTIVIEW float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0); #else // USE_MULTIVIEW @@ -1798,7 +1798,7 @@ void fragment_shader(in SceneData scene_data) { shadow = float(shadow1 >> ((i - 4u) * 8u) & 0xFFu) / 255.0; } - shadow = shadow * directional_lights.data[i].shadow_opacity + 1.0 - directional_lights.data[i].shadow_opacity; + shadow = mix(1.0, shadow, directional_lights.data[i].shadow_opacity); #endif blur_shadow(shadow); @@ -2082,7 +2082,7 @@ void fragment_shader(in SceneData scene_data) { float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - //store as 8985 to have 2 extra neighbour bits + //store as 8985 to have 2 extra neighbor bits uint light_rgbe = ((uint(sRed) & 0x1FFu) >> 1) | ((uint(sGreen) & 0x1FFu) << 8) | (((uint(sBlue) & 0x1FFu) >> 1) << 17) | ((uint(exps) & 0x1Fu) << 25); imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 5e64d4e651..2966a2ff65 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -1515,6 +1515,8 @@ void main() { } else { shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; } + + shadow = mix(1.0, shadow, directional_lights.data[i].shadow_opacity); #endif blur_shadow(shadow); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 673fc25595..33e35a7a64 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -568,8 +568,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged r_directional_light_count = 0; r_positional_light_count = 0; - Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin); - omni_light_count = 0; spot_light_count = 0; @@ -720,7 +718,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged } Transform3D light_transform = light_instance->transform; - const real_t distance = camera_plane.distance_to(light_transform.origin); + const real_t distance = p_camera_transform.origin.distance_to(light_transform.origin); if (light->distance_fade) { const float fade_begin = light->distance_fade_begin; @@ -745,7 +743,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged } Transform3D light_transform = light_instance->transform; - const real_t distance = camera_plane.distance_to(light_transform.origin); + const real_t distance = p_camera_transform.origin.distance_to(light_transform.origin); if (light->distance_fade) { const float fade_begin = light->distance_fade_begin; @@ -787,6 +785,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; LightInstance *light_instance = (i < omni_light_count) ? omni_light_sort[index].light_instance : spot_light_sort[index].light_instance; Light *light = (i < omni_light_count) ? omni_light_sort[index].light : spot_light_sort[index].light; + real_t distance = (i < omni_light_count) ? omni_light_sort[index].depth : spot_light_sort[index].depth; if (using_forward_ids) { forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index); @@ -803,7 +802,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged float fade_begin = 0.0; float fade_shadow = 0.0; float fade_length = 0.0; - real_t distance = 0.0; float fade = 1.0; float shadow_opacity_fade = 1.0; @@ -811,7 +809,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged fade_begin = light->distance_fade_begin; fade_shadow = light->distance_fade_shadow; fade_length = light->distance_fade_length; - distance = camera_plane.distance_to(light_transform.origin); // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. if (distance > fade_begin) { diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 62da62403f..46a0d85ba8 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -842,15 +842,15 @@ void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int } void MeshStorage::_mesh_instance_clear(MeshInstance *mi) { - for (uint32_t i = 0; i < mi->surfaces.size(); i++) { - if (mi->surfaces[i].versions) { - for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) { - RD::get_singleton()->free(mi->surfaces[i].versions[j].vertex_array); + for (const RendererRD::MeshStorage::MeshInstance::Surface surface : mi->surfaces) { + if (surface.versions) { + for (uint32_t j = 0; j < surface.version_count; j++) { + RD::get_singleton()->free(surface.versions[j].vertex_array); } - memfree(mi->surfaces[i].versions); + memfree(surface.versions); } - if (mi->surfaces[i].vertex_buffer.is_valid()) { - RD::get_singleton()->free(mi->surfaces[i].vertex_buffer); + if (surface.vertex_buffer.is_valid()) { + RD::get_singleton()->free(surface.vertex_buffer); } } mi->surfaces.clear(); @@ -866,8 +866,8 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) { void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) { if (mesh->blend_shape_count > 0 && mi->blend_weights_buffer.is_null()) { mi->blend_weights.resize(mesh->blend_shape_count); - for (uint32_t i = 0; i < mi->blend_weights.size(); i++) { - mi->blend_weights[i] = 0; + for (float &weight : mi->blend_weights) { + weight = 0; } mi->blend_weights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * mi->blend_weights.size(), mi->blend_weights.to_byte_array()); mi->weights_dirty = true; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 6401d0f5d0..f4c3e769a8 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -851,9 +851,9 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta collision_heightmap_texture = p_particles->sdf_collision_texture; //replace in all other history frames where used because parameters are no longer valid if screen moves - for (uint32_t i = 1; i < p_particles->frame_history.size(); i++) { - if (p_particles->frame_history[i].collider_count > 0 && p_particles->frame_history[i].colliders[0].type == ParticlesFrameParams::COLLISION_TYPE_2D_SDF) { - p_particles->frame_history[i].colliders[0] = frame_params.colliders[0]; + for (ParticlesFrameParams ¶ms : p_particles->frame_history) { + if (params.collider_count > 0 && params.colliders[0].type == ParticlesFrameParams::COLLISION_TYPE_2D_SDF) { + params.colliders[0] = frame_params.colliders[0]; } } } @@ -1415,7 +1415,6 @@ void ParticlesStorage::update_particles() { } bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0; - bool updated = false; if (particles->clear && particles->pre_process_time > 0.0) { double frame_time; @@ -1430,7 +1429,6 @@ void ParticlesStorage::update_particles() { while (todo >= 0) { _particles_process(particles, frame_time); todo -= frame_time; - updated = true; } } @@ -1452,10 +1450,9 @@ void ParticlesStorage::update_particles() { } double todo = particles->frame_remainder + delta; - while (todo >= frame_time || (particles->clear && !updated)) { + while (todo >= frame_time || particles->clear) { _particles_process(particles, frame_time); todo -= decr; - updated = true; } particles->frame_remainder = todo; @@ -1463,16 +1460,16 @@ void ParticlesStorage::update_particles() { } else { if (zero_time_scale) { _particles_process(particles, 0.0); - updated = true; } else { _particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time()); - updated = true; } } - //copy particles to instance buffer + // Ensure that memory is initialized (the code above should ensure that _particles_process is always called at least once upon clearing). + DEV_ASSERT(!particles->clear); - if (updated && particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { + // Copy particles to instance buffer. + if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { //does not need view dependent operation, do copy here ParticlesShader::CopyPushConstant copy_push_constant; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index 31377a10a0..7771f75a65 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -251,7 +251,7 @@ RID RenderSceneBuffersRD::create_texture(const StringName &p_context, const Stri } RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view, bool p_unique) { - // TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimisation. + // TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimization. NTKey key(p_context, p_texture_name); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 06fda8fa9e..e8d9f486bb 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2206,6 +2206,12 @@ void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Tr di->transform = p_transform; } +void TextureStorage::decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + ERR_FAIL_COND(!di); + di->sorting_offset = p_sorting_offset; +} + /* DECAL DATA API */ void TextureStorage::free_decal_data() { @@ -2233,7 +2239,7 @@ void TextureStorage::set_max_decals(const uint32_t p_max_decals) { decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); } -void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) { +void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_xform) { ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton(); Transform3D uv_xform; @@ -2257,7 +2263,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D xform = decal_instance->transform; - real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + real_t distance = p_camera_xform.origin.distance_to(xform.origin); if (decal->distance_fade) { float fade_begin = decal->distance_fade_begin; @@ -2272,7 +2278,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const decal_sort[decal_count].decal_instance = decal_instance; decal_sort[decal_count].decal = decal; - decal_sort[decal_count].depth = distance; + decal_sort[decal_count].depth = distance - decal_instance->sorting_offset; decal_count++; } @@ -2292,11 +2298,10 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const decal_instance->cull_mask = decal->cull_mask; - Transform3D xform = decal_instance->transform; float fade = 1.0; if (decal->distance_fade) { - const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + const real_t distance = decal_sort[i].depth + decal_instance->sorting_offset; const float fade_begin = decal->distance_fade_begin; const float fade_length = decal->distance_fade_length; @@ -2312,11 +2317,16 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D scale_xform; scale_xform.basis.scale(decal_extents); - Transform3D to_decal_xform = (p_camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse(); + + Transform3D xform = decal_instance->transform; + + Transform3D camera_inverse_xform = p_camera_xform.affine_inverse(); + + Transform3D to_decal_xform = (camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse(); MaterialStorage::store_transform(to_decal_xform, dd.xform); Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized(); - normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine + normal = camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine dd.normal[0] = normal.x; dd.normal[1] = normal.y; @@ -2350,7 +2360,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const dd.normal_rect[2] = rect.size.x; dd.normal_rect[3] = rect.size.y; - Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); + Basis normal_xform = camera_inverse_xform.basis * xform.basis.orthonormalized(); MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform); } else { dd.normal_rect[0] = 0; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 1558342c3b..ea0df0b459 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -258,6 +258,7 @@ private: struct DecalInstance { RID decal; Transform3D transform; + float sorting_offset = 0.0; uint32_t cull_mask = 0; RendererRD::ForwardID forward_id = -1; }; @@ -646,6 +647,7 @@ public: virtual RID decal_instance_create(RID p_decal) override; virtual void decal_instance_free(RID p_decal_instance) override; virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) override; + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override; _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal_instance) const { DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); @@ -677,7 +679,7 @@ public: void free_decal_data(); void set_max_decals(const uint32_t p_max_decals); RID get_decal_buffer() { return decal_buffer; } - void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform); + void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_xform); /* RENDER TARGET API */ diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 2ea813aab0..9011cdd98a 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -694,6 +694,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { instance->base_data = decal; decal->instance = RSG::texture_storage->decal_instance_create(p_base); + RSG::texture_storage->decal_instance_set_sorting_offset(decal->instance, instance->sorting_offset); } break; case RS::INSTANCE_LIGHTMAP: { InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); @@ -748,6 +749,10 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { switch (instance->base_type) { case RS::INSTANCE_LIGHT: { InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + if (instance->visible && RSG::light_storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + instance->scenario->dynamic_lights.erase(light->instance); + } + #ifdef DEBUG_ENABLED if (light->geometries.size()) { ERR_PRINT("BUG, indexing did not unpair geometries from light."); @@ -867,6 +872,9 @@ void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); geom->geometry_instance->set_pivot_data(p_sorting_offset, p_use_aabb_center); + } else if (instance->base_type == RS::INSTANCE_DECAL && instance->base_data) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data); + RSG::texture_storage->decal_instance_set_sorting_offset(decal->instance, instance->sorting_offset); } } @@ -2820,7 +2828,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); + cull_data.cull->lock.lock(); geom->geometry_instance->set_softshadow_projector_pairing(geom->softshadow_count > 0, geom->projector_count > 0); + cull_data.cull->lock.unlock(); idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY); } @@ -2887,7 +2897,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); } ERR_FAIL_NULL(geom->geometry_instance); + cull_data.cull->lock.lock(); geom->geometry_instance->set_lightmap_capture(sh); + cull_data.cull->lock.unlock(); idata.instance->last_frame_pass = frame_number; } @@ -3084,15 +3096,15 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c #endif if (cull_to > thread_cull_threshold) { //multiple threads - for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { - scene_cull_result_threads[i].clear(); + for (InstanceCullResult &thread : scene_cull_result_threads) { + thread.clear(); } WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RendererSceneCull::_scene_cull_threaded, &cull_data, scene_cull_result_threads.size(), -1, true, SNAME("RenderCullInstances")); WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); - for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { - scene_cull_result.append_from(scene_cull_result_threads[i]); + for (InstanceCullResult &thread : scene_cull_result_threads) { + scene_cull_result.append_from(thread); } } else { @@ -4122,8 +4134,8 @@ RendererSceneCull::RendererSceneCull() { scene_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); scene_cull_result_threads.resize(WorkerThreadPool::get_singleton()->get_thread_count()); - for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { - scene_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + for (InstanceCullResult &thread : scene_cull_result_threads) { + thread.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); } indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); @@ -4151,8 +4163,8 @@ RendererSceneCull::~RendererSceneCull() { } scene_cull_result.reset(); - for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { - scene_cull_result_threads[i].reset(); + for (InstanceCullResult &thread : scene_cull_result_threads) { + thread.reset(); } scene_cull_result_threads.clear(); diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index b82019dd9d..3886f5b379 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1138,6 +1138,7 @@ void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::Viewport void RendererViewport::viewport_set_use_taa(RID p_viewport, bool p_use_taa) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); + ERR_FAIL_COND_EDMSG(OS::get_singleton()->get_current_rendering_method() != "forward_plus", "TAA is only available when using the Forward+ renderer."); if (viewport->use_taa == p_use_taa) { return; diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 626da90168..68542f32af 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -909,9 +909,6 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene if (p_default_actions.renames.has(vnode->name)) { code = p_default_actions.renames[vnode->name]; - if (vnode->name == "SCREEN_TEXTURE") { - r_gen_code.uses_screen_texture_mipmaps = true; - } } else { if (shader->uniforms.has(vnode->name)) { //its a uniform! @@ -919,29 +916,22 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene if (u.texture_order >= 0) { StringName name = vnode->name; if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) { - name = "SCREEN_TEXTURE"; + name = "color_buffer"; if (u.filter >= ShaderLanguage::FILTER_NEAREST_MIPMAP) { r_gen_code.uses_screen_texture_mipmaps = true; } + r_gen_code.uses_screen_texture = true; } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) { - name = "NORMAL_ROUGHNESS_TEXTURE"; + name = "normal_roughness_buffer"; + r_gen_code.uses_normal_roughness_texture = true; } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) { - name = "DEPTH_TEXTURE"; + name = "depth_buffer"; + r_gen_code.uses_depth_texture = true; } else { name = _mkid(vnode->name); //texture, use as is } - if (p_default_actions.renames.has(name)) { - code = p_default_actions.renames[name]; - } else { - code = name; - } - - if (p_actions.usage_flag_pointers.has(name) && !used_flag_pointers.has(name)) { - *p_actions.usage_flag_pointers[name] = true; - used_flag_pointers.insert(name); - } - + code = name; } else { //a scalar or vector if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { @@ -1251,16 +1241,20 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } if (correct_texture_uniform) { - //TODO Needs to detect screen_texture hint as well - is_screen_texture = (texture_uniform == "SCREEN_TEXTURE"); - String sampler_name; + bool is_normal_roughness_texture = false; if (actions.custom_samplers.has(texture_uniform)) { sampler_name = actions.custom_samplers[texture_uniform]; } else { if (shader->uniforms.has(texture_uniform)) { - sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); + const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[texture_uniform]; + if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) { + is_screen_texture = true; + } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) { + is_normal_roughness_texture = true; + } + sampler_name = _get_sampler_name(u.filter, u.repeat); } else { bool found = false; @@ -1287,7 +1281,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } String data_type_name = ""; - if (texture_uniform == "NORMAL_ROUGHNESS_TEXTURE") { + if (is_normal_roughness_texture) { data_type_name = "multiviewSampler"; normal_roughness_texture_used = true; } else { @@ -1515,6 +1509,9 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident r_gen_code.uses_vertex_time = false; r_gen_code.uses_global_textures = false; r_gen_code.uses_screen_texture_mipmaps = false; + r_gen_code.uses_screen_texture = false; + r_gen_code.uses_depth_texture = false; + r_gen_code.uses_normal_roughness_texture = false; used_name_defines.clear(); used_rmode_defines.clear(); diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h index eeb2916160..43bea213da 100644 --- a/servers/rendering/shader_compiler.h +++ b/servers/rendering/shader_compiler.h @@ -81,6 +81,9 @@ public: bool uses_fragment_time; bool uses_vertex_time; bool uses_screen_texture_mipmaps; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_roughness_texture; }; struct DefaultIdentifierActions { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 59a2ff66f3..ba7ffda00a 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5399,6 +5399,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } else { if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) { + if (identifier == "SCREEN_TEXTURE" || identifier == "DEPTH_TEXTURE" || identifier == "NORMAL_ROUGHNESS_TEXTURE") { + String name = String(identifier); + String name_lower = name.to_lower(); + _set_error(vformat(RTR("%s has been removed in favor of using hint_%s with a uniform.\nTo continue with minimal code changes add 'uniform sampler2D %s : hint_%s, filter_linear_mipmap;' near the top of your shader."), name, name_lower, name, name_lower)); + return nullptr; + } _set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier))); return nullptr; } @@ -8691,14 +8697,17 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f case TK_HINT_SCREEN_TEXTURE: { new_hint = ShaderNode::Uniform::HINT_SCREEN_TEXTURE; --texture_uniforms; + --texture_binding; } break; case TK_HINT_NORMAL_ROUGHNESS_TEXTURE: { new_hint = ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE; --texture_uniforms; + --texture_binding; } break; case TK_HINT_DEPTH_TEXTURE: { new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE; --texture_uniforms; + --texture_binding; } break; case TK_FILTER_NEAREST: { new_filter = FILTER_NEAREST; diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 40c8acffe5..97efd2df94 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -330,8 +330,8 @@ String ShaderPreprocessor::vector_to_string(const LocalVector<char32_t> &p_v, in String ShaderPreprocessor::tokens_to_string(const LocalVector<Token> &p_tokens) { LocalVector<char32_t> result; - for (uint32_t i = 0; i < p_tokens.size(); i++) { - result.push_back(p_tokens[i].text); + for (const Token &token : p_tokens) { + result.push_back(token.text); } return vector_to_string(result); } @@ -1081,21 +1081,17 @@ ShaderPreprocessor::Define *ShaderPreprocessor::create_define(const String &p_bo return define; } -void ShaderPreprocessor::clear() { - if (state_owner && state != nullptr) { +void ShaderPreprocessor::clear_state() { + if (state != nullptr) { for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) { memdelete(E->get()); } - - memdelete(state); + state->defines.clear(); } - state_owner = false; state = nullptr; } Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, String &r_result) { - clear(); - output.clear(); state = p_state; @@ -1242,6 +1238,9 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen } } } + + clear_state(); + return err; } @@ -1273,5 +1272,4 @@ ShaderPreprocessor::ShaderPreprocessor() { } ShaderPreprocessor::~ShaderPreprocessor() { - clear(); } diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h index f5902c64ca..6e5533c575 100644 --- a/servers/rendering/shader_preprocessor.h +++ b/servers/rendering/shader_preprocessor.h @@ -167,7 +167,6 @@ private: private: LocalVector<char32_t> output; State *state = nullptr; - bool state_owner = false; private: static bool is_char_word(char32_t p_char); @@ -211,7 +210,7 @@ private: static Define *create_define(const String &p_body); - void clear(); + void clear_state(); Error preprocess(State *p_state, const String &p_code, String &r_result); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 38dc806370..ba39328b2e 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -138,9 +138,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); @@ -267,7 +264,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true; diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 92149b0064..4c4a84d04e 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -127,6 +127,7 @@ public: virtual RID decal_instance_create(RID p_decal) = 0; virtual void decal_instance_free(RID p_decal_instance) = 0; virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) = 0; + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) = 0; /* RENDER TARGET */ diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index e24b2af976..4ef562adcb 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -996,6 +996,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa if (index_array_len) { List<Variant> keys; p_lods.get_key_list(&keys); + keys.sort(); // otherwise lod levels may get skipped for (const Variant &E : keys) { float distance = E; ERR_CONTINUE(distance <= 0.0); @@ -1826,6 +1827,7 @@ void RenderingServer::_bind_methods() { BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES); BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE); BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS); + BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); @@ -2593,7 +2595,7 @@ void RenderingServer::_bind_methods() { /* Primitives */ ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(-1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(-1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); @@ -2800,9 +2802,7 @@ void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry Vector<Vector3> vertices; Vector<Vector3> normals; - for (uint32_t i = 0; i < p_mesh_data.faces.size(); i++) { - const Geometry3D::MeshData::Face &f = p_mesh_data.faces[i]; - + for (const Geometry3D::MeshData::Face &f : p_mesh_data.faces) { for (uint32_t j = 2; j < f.indices.size(); j++) { vertices.push_back(p_mesh_data.vertices[f.indices[0]]); normals.push_back(f.plane.normal); @@ -2961,9 +2961,9 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"), 64); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"), 1); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"), 512); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 4b51099ef0..231139e9df 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1335,7 +1335,7 @@ public: }; virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false) = 0; - virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; + virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 997b83e32d..cbf37f25d6 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -1373,8 +1373,8 @@ String TextServerExtension::string_to_lower(const String &p_string, const String return p_string; } -TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { - TypedArray<Vector2i> ret; +TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { + TypedArray<Vector3i> ret; GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret); return ret; } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index fb784f5471..8536836983 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -521,8 +521,8 @@ public: GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &); GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &); - TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; - GDVIRTUAL3RC(TypedArray<Vector2i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); + TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override; virtual bool spoof_check(const String &p_string) const override; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index d339533688..027109b67d 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -483,6 +483,7 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(DIRECTION_AUTO); BIND_ENUM_CONSTANT(DIRECTION_LTR); BIND_ENUM_CONSTANT(DIRECTION_RTL); + BIND_ENUM_CONSTANT(DIRECTION_INHERITED); /* Orientation */ BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL); @@ -599,7 +600,7 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST); - BIND_ENUM_CONSTANT(STRUCTURED_TEXT_NONE); + BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM); } @@ -1692,22 +1693,22 @@ String TextServer::strip_diacritics(const String &p_string) const { return result; } -TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { - TypedArray<Vector2i> ret; +TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { + TypedArray<Vector3i> ret; switch (p_parser_type) { case STRUCTURED_TEXT_URI: { int prev = 0; for (int i = 0; i < p_text.length(); i++) { if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) { if (prev != i) { - ret.push_back(Vector2i(prev, i)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); } - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } } if (prev != p_text.length()) { - ret.push_back(Vector2i(prev, p_text.length())); + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); } } break; case STRUCTURED_TEXT_FILE: { @@ -1715,14 +1716,14 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa for (int i = 0; i < p_text.length(); i++) { if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) { if (prev != i) { - ret.push_back(Vector2i(prev, i)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); } - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } } if (prev != p_text.length()) { - ret.push_back(Vector2i(prev, p_text.length())); + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); } } break; case STRUCTURED_TEXT_EMAIL: { @@ -1731,19 +1732,19 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa for (int i = 0; i < p_text.length(); i++) { if ((p_text[i] == '@') && local) { // Add full "local" as single context. local = false; - ret.push_back(Vector2i(prev, i)); - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context. if (prev != i) { - ret.push_back(Vector2i(prev, i)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); } - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } } if (prev != p_text.length()) { - ret.push_back(Vector2i(prev, p_text.length())); + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); } } break; case STRUCTURED_TEXT_LIST: { @@ -1752,18 +1753,97 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa int prev = 0; for (int i = 0; i < tags.size(); i++) { if (prev != i) { - ret.push_back(Vector2i(prev, prev + tags[i].length())); + ret.push_back(Vector3i(prev, prev + tags[i].length(), TextServer::DIRECTION_INHERITED)); } - ret.push_back(Vector2i(prev + tags[i].length(), prev + tags[i].length() + 1)); + ret.push_back(Vector3i(prev + tags[i].length(), prev + tags[i].length() + 1, TextServer::DIRECTION_INHERITED)); prev = prev + tags[i].length() + 1; } } } break; + case STRUCTURED_TEXT_GDSCRIPT: { + bool in_string_literal = false; + bool in_string_literal_single = false; + bool in_id = false; + + int prev = 0; + for (int i = 0; i < p_text.length(); i++) { + char32_t c = p_text[i]; + if (in_string_literal) { + if (c == '\\') { + i++; + continue; // Skip escaped chars. + } else if (c == '\"') { + // String literal end, push string and ". + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal = false; + } + } else if (in_string_literal_single) { + if (c == '\\') { + i++; + continue; // Skip escaped chars. + } else if (c == '\'') { + // String literal end, push string and '. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal_single = false; + } + } else if (in_id) { + if (!is_unicode_identifier_continue(c)) { + // End of id, push id. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i; + in_id = false; + } + } else if (is_unicode_identifier_start(c)) { + // Start of new id, push prev element. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i; + in_id = true; + } else if (c == '\"') { + // String literal start, push prev element and ". + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal = true; + } else if (c == '\'') { + // String literal start, push prev element and '. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal_single = true; + } else if (c == '#') { + // Start of comment, push prev element and #, skip the rest of the text. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + break; + } + } + if (prev < p_text.length()) { + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); + } + } break; case STRUCTURED_TEXT_CUSTOM: - case STRUCTURED_TEXT_NONE: case STRUCTURED_TEXT_DEFAULT: default: { - ret.push_back(Vector2i(0, p_text.length())); + ret.push_back(Vector3i(0, p_text.length(), TextServer::DIRECTION_INHERITED)); } } return ret; diff --git a/servers/text_server.h b/servers/text_server.h index a56c7d8b23..a91d367e97 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -65,7 +65,8 @@ public: enum Direction { DIRECTION_AUTO, DIRECTION_LTR, - DIRECTION_RTL + DIRECTION_RTL, + DIRECTION_INHERITED, }; enum Orientation { @@ -198,7 +199,7 @@ public: STRUCTURED_TEXT_FILE, STRUCTURED_TEXT_EMAIL, STRUCTURED_TEXT_LIST, - STRUCTURED_TEXT_NONE, + STRUCTURED_TEXT_GDSCRIPT, STRUCTURED_TEXT_CUSTOM }; @@ -505,7 +506,7 @@ public: virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; - TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; virtual void cleanup() {} diff --git a/servers/xr_server.h b/servers/xr_server.h index 086a18c111..04cf6c1d1e 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -111,7 +111,7 @@ public: Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode. This scale basically effects the unit size relationship to real world size. - I may remove access to this property in GDScript in favour of exposing it on the XROrigin3D node + I may remove access to this property in GDScript in favor of exposing it on the XROrigin3D node */ double get_world_scale() const; void set_world_scale(double p_world_scale); diff --git a/tests/core/io/test_xml_parser.h b/tests/core/io/test_xml_parser.h index f4e3f34be2..40cbea2dab 100644 --- a/tests/core/io/test_xml_parser.h +++ b/tests/core/io/test_xml_parser.h @@ -54,7 +54,7 @@ TEST_CASE("[XMLParser] End-to-end") { CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_ELEMENT); CHECK(parser.get_node_name() == "top"); CHECK(parser.has_attribute("attr")); - CHECK(parser.get_attribute_value("attr") == "attr value"); + CHECK(parser.get_named_attribute_value("attr") == "attr value"); CHECK(parser.read() == OK); CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_TEXT); diff --git a/tests/core/math/test_geometry_3d.h b/tests/core/math/test_geometry_3d.h index 8d57bd5319..46a99aa4b6 100644 --- a/tests/core/math/test_geometry_3d.h +++ b/tests/core/math/test_geometry_3d.h @@ -388,13 +388,13 @@ TEST_CASE("[Geometry3D] Segment Intersects Triangle") { TEST_CASE("[Geometry3D] Triangle and Box Overlap") { struct Case { - Vector3 box_centre; + Vector3 box_center; Vector3 box_half_size; Vector3 *tri_verts = nullptr; bool want; Case(){}; - Case(Vector3 p_centre, Vector3 p_half_size, Vector3 *p_verts, bool p_want) : - box_centre(p_centre), box_half_size(p_half_size), tri_verts(p_verts), want(p_want){}; + Case(Vector3 p_center, Vector3 p_half_size, Vector3 *p_verts, bool p_want) : + box_center(p_center), box_half_size(p_half_size), tri_verts(p_verts), want(p_want){}; }; Vector<Case> tt; Vector3 GoodTriangle[3] = { Vector3(3, 2, 3), Vector3(2, 2, 1), Vector3(2, 1, 1) }; @@ -403,7 +403,7 @@ TEST_CASE("[Geometry3D] Triangle and Box Overlap") { tt.push_back(Case(Vector3(1000, 1000, 1000), Vector3(1, 1, 1), BadTriangle, false)); for (int i = 0; i < tt.size(); ++i) { Case current_case = tt[i]; - bool output = Geometry3D::triangle_box_overlap(current_case.box_centre, current_case.box_half_size, current_case.tri_verts); + bool output = Geometry3D::triangle_box_overlap(current_case.box_center, current_case.box_half_size, current_case.tri_verts); CHECK(output == current_case.want); } } diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h index 4d9feeb4fa..b2a2ecc3bf 100644 --- a/tests/scene/test_arraymesh.h +++ b/tests/scene/test_arraymesh.h @@ -114,6 +114,17 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") { CHECK(mesh->get_blend_shape_count() == 0); } + SUBCASE("Can't add surface with incorrect number of blend shapes.") { + mesh->add_blend_shape(name_a); + mesh->add_blend_shape(name_b); + Ref<CylinderMesh> cylinder = memnew(CylinderMesh); + Array cylinder_array{}; + ERR_PRINT_OFF + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array); + ERR_PRINT_ON + CHECK(mesh->get_surface_count() == 0); + } + SUBCASE("Can't clear blend shapes after surface had been added.") { mesh->add_blend_shape(name_a); mesh->add_blend_shape(name_b); @@ -121,7 +132,15 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") { Array cylinder_array{}; cylinder_array.resize(Mesh::ARRAY_MAX); cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f); - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array); + Array blend_shape{}; + blend_shape.resize(Mesh::ARRAY_MAX); + blend_shape[Mesh::ARRAY_VERTEX] = cylinder_array[Mesh::ARRAY_VERTEX]; + blend_shape[Mesh::ARRAY_NORMAL] = cylinder_array[Mesh::ARRAY_NORMAL]; + blend_shape[Mesh::ARRAY_TANGENT] = cylinder_array[Mesh::ARRAY_TANGENT]; + Array blend_shapes{}; + blend_shapes.push_back(blend_shape); + blend_shapes.push_back(blend_shape); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend_shapes); ERR_PRINT_OFF mesh->clear_blend_shapes(); diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h index 5447c99a64..828029dabe 100644 --- a/tests/scene/test_code_edit.h +++ b/tests/scene/test_code_edit.h @@ -1954,7 +1954,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { code_edit->set_editable(false); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "\t"); code_edit->unindent_lines(); @@ -1963,16 +1963,9 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { code_edit->set_editable(true); /* Simple unindent. */ - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == ""); - /* Should inindent inplace. */ - code_edit->set_text(""); - code_edit->insert_text_at_caret("test\t"); - - code_edit->do_unindent(); - CHECK(code_edit->get_line(0) == "test"); - /* Backspace does a simple unindent. */ code_edit->set_text(""); code_edit->insert_text_at_caret("\t"); @@ -1987,7 +1980,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { /* Caret on col zero unindent line. */ code_edit->set_text("\t\ttest"); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "\ttest"); /* Check input action. */ @@ -1998,34 +1991,34 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { /* Selection does entire line. */ code_edit->set_text("\t\ttest"); code_edit->select_all(); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "\ttest"); /* Handles multiple lines. */ code_edit->set_text("\ttest\n\ttext"); code_edit->select_all(); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "test"); CHECK(code_edit->get_line(1) == "text"); /* Do not unindent line if last col is zero. */ code_edit->set_text("\ttest\n\ttext"); code_edit->select(0, 0, 1, 0); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "test"); CHECK(code_edit->get_line(1) == "\ttext"); /* Unindent even if last column of first line. */ code_edit->set_text("\ttest\n\ttext"); code_edit->select(0, 5, 1, 1); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "test"); CHECK(code_edit->get_line(1) == "text"); /* Check selection is adjusted. */ code_edit->set_text("\ttest"); code_edit->select(0, 1, 0, 2); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_selection_from_column() == 0); CHECK(code_edit->get_selection_to_column() == 1); CHECK(code_edit->get_line(0) == "test"); @@ -2041,7 +2034,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { code_edit->set_editable(false); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == " "); code_edit->unindent_lines(); @@ -2050,16 +2043,9 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { code_edit->set_editable(true); /* Simple unindent. */ - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == ""); - /* Should inindent inplace. */ - code_edit->set_text(""); - code_edit->insert_text_at_caret("test "); - - code_edit->do_unindent(); - CHECK(code_edit->get_line(0) == "test"); - /* Backspace does a simple unindent. */ code_edit->set_text(""); code_edit->insert_text_at_caret(" "); @@ -2080,12 +2066,12 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { /* Caret on col zero unindent line. */ code_edit->set_text(" test"); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == " test"); /* Only as far as needed */ code_edit->set_text(" test"); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == " test"); /* Check input action. */ @@ -2096,34 +2082,34 @@ TEST_CASE("[SceneTree][CodeEdit] indent") { /* Selection does entire line. */ code_edit->set_text(" test"); code_edit->select_all(); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == " test"); /* Handles multiple lines. */ code_edit->set_text(" test\n text"); code_edit->select_all(); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "test"); CHECK(code_edit->get_line(1) == "text"); /* Do not unindent line if last col is zero. */ code_edit->set_text(" test\n text"); code_edit->select(0, 0, 1, 0); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "test"); CHECK(code_edit->get_line(1) == " text"); /* Unindent even if last column of first line. */ code_edit->set_text(" test\n text"); code_edit->select(0, 5, 1, 1); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_line(0) == "test"); CHECK(code_edit->get_line(1) == "text"); /* Check selection is adjusted. */ code_edit->set_text(" test"); code_edit->select(0, 4, 0, 5); - code_edit->do_unindent(); + code_edit->unindent_lines(); CHECK(code_edit->get_selection_from_column() == 0); CHECK(code_edit->get_selection_to_column() == 1); CHECK(code_edit->get_line(0) == "test"); @@ -2787,7 +2773,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") { CHECK(code_edit->get_line(0) == "''"); CHECK(code_edit->get_caret_column() == 1); - /* Move out from centre, Should match and insert larger key. */ + /* Move out from center, Should match and insert larger key. */ SEND_GUI_ACTION(code_edit, "ui_text_caret_right"); SEND_GUI_KEY_EVENT(code_edit, Key::APOSTROPHE); CHECK(code_edit->get_line(0) == "''''''"); diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h index 6cdb5fb0a5..9232a3020d 100644 --- a/tests/scene/test_primitives.h +++ b/tests/scene/test_primitives.h @@ -734,7 +734,7 @@ TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") { text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_FILE || text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL || text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_LIST || - text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_NONE || + text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_GDSCRIPT || text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_CUSTOM)); CHECK(text->get_structured_text_bidi_override_options().size() >= 0); CHECK(text->get_width() > 0); diff --git a/thirdparty/README.md b/thirdparty/README.md index 33f835cbcd..38001b8782 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -17,6 +17,18 @@ Files extracted from upstream source: - `license.txt` +## astcenc + +- Upstream: https://github.com/ARM-software/astc-encoder +- Version: 4.3.0 (ec83dda79fcefe07f69cdae7ed980d169bf2c4d4, 2023) +- License: Apache 2.0 + +Files extracted from upstream source: + +- `astcenc_*` and `astcenc.h` files from `Source` +- `LICENSE.txt` + + ## basis_universal - Upstream: https://github.com/BinomialLLC/basis_universal diff --git a/thirdparty/astcenc/LICENSE.txt b/thirdparty/astcenc/LICENSE.txt new file mode 100644 index 0000000000..b82735a310 --- /dev/null +++ b/thirdparty/astcenc/LICENSE.txt @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/thirdparty/astcenc/astcenc.h b/thirdparty/astcenc/astcenc.h new file mode 100644 index 0000000000..70ae783373 --- /dev/null +++ b/thirdparty/astcenc/astcenc.h @@ -0,0 +1,815 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2020-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief The core astcenc codec library interface. + * + * This interface is the entry point to the core astcenc codec. It aims to be easy to use for + * non-experts, but also to allow experts to have fine control over the compressor heuristics if + * needed. The core codec only handles compression and decompression, transferring all inputs and + * outputs via memory buffers. To catch obvious input/output buffer sizing issues, which can cause + * security and stability problems, all transfer buffers are explicitly sized. + * + * While the aim is that we keep this interface mostly stable, it should be viewed as a mutable + * interface tied to a specific source version. We are not trying to maintain backwards + * compatibility across codec versions. + * + * The API state management is based around an explicit context object, which is the context for all + * allocated memory resources needed to compress and decompress a single image. A context can be + * used to sequentially compress multiple images using the same configuration, allowing setup + * overheads to be amortized over multiple images, which is particularly important when images are + * small. + * + * Multi-threading can be used two ways. + * + * * An application wishing to process multiple images in parallel can allocate multiple + * contexts and assign each context to a thread. + * * An application wishing to process a single image in using multiple threads can configure + * contexts for multi-threaded use, and invoke astcenc_compress/decompress() once per thread + * for faster processing. The caller is responsible for creating the worker threads, and + * synchronizing between images. + * + * Threading + * ========= + * + * In pseudo-code, the usage for manual user threading looks like this: + * + * // Configure the compressor run + * astcenc_config my_config; + * astcenc_config_init(..., &my_config); + * + * // Power users can tweak <my_config> settings here ... + * + * // Allocate working state given config and thread_count + * astcenc_context* my_context; + * astcenc_context_alloc(&my_config, thread_count, &my_context); + * + * // Compress each image using these config settings + * foreach image: + * // For each thread in the thread pool + * for i in range(0, thread_count): + * astcenc_compress_image(my_context, &my_input, my_output, i); + * + * astcenc_compress_reset(my_context); + * + * // Clean up + * astcenc_context_free(my_context); + * + * Images + * ====== + * + * The codec supports compressing single images, which can be either 2D images or volumetric 3D + * images. Calling code is responsible for any handling of aggregate types, such as mipmap chains, + * texture arrays, or sliced 3D textures. + * + * Images are passed in as an astcenc_image structure. Inputs can be either 8-bit unorm, 16-bit + * half-float, or 32-bit float, as indicated by the data_type field. + * + * Images can be any dimension; there is no requirement to be a multiple of the ASTC block size. + * + * Data is always passed in as 4 color components, and accessed as an array of 2D image slices. Data + * within an image slice is always tightly packed without padding. Addressing looks like this: + * + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 ] // Red + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 1] // Green + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 2] // Blue + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 3] // Alpha + * + * Common compressor usage + * ======================= + * + * One of the most important things for coding image quality is to align the input data component + * count with the ASTC color endpoint mode. This avoids wasting bits encoding components you don't + * actually need in the endpoint colors. + * + * | Input data | Encoding swizzle | Sampling swizzle | + * | ------------ | ---------------- | ---------------- | + * | 1 component | RRR1 | .[rgb] | + * | 2 components | RRRG | .[rgb]a | + * | 3 components | RGB1 | .rgb | + * | 4 components | RGBA | .rgba | + * + * The 1 and 2 component modes recommend sampling from "g" to recover the luminance value as this + * provide best compatibility with other texture formats where the green component may be stored at + * higher precision than the others, such as RGB565. For ASTC any of the RGB components can be used; + * the luminance endpoint component will be returned for all three. + * + * When using the normal map compression mode ASTC will store normals as a two component X+Y map. + * Input images must contain unit-length normalized and should be passed in using a two component + * swizzle. The astcenc command line tool defaults to an RRRG swizzle, but some developers prefer + * to use GGGR for compatability with BC5n which will work just as well. The Z component can be + * recovered programmatically in shader code, using knowledge that the vector is unit length and + * that Z must be positive for a tangent-space normal map. + * + * Decompress-only usage + * ===================== + * + * For some use cases it is useful to have a cut-down context and/or library which supports + * decompression but not compression. + * + * A context can be made decompress-only using the ASTCENC_FLG_DECOMPRESS_ONLY flag when the context + * is allocated. These contexts have lower dynamic memory footprint than a full context. + * + * The entire library can be made decompress-only by building the files with the define + * ASTCENC_DECOMPRESS_ONLY set. In this build the context will be smaller, and the library will + * exclude the functionality which is only needed for compression. This reduces the binary size by + * ~180KB. For these builds contexts must be created with the ASTCENC_FLG_DECOMPRESS_ONLY flag. + * + * Note that context structures returned by a library built as decompress-only are incompatible with + * a library built with compression included, and visa versa, as they have different sizes and + * memory layout. + * + * Self-decompress-only usage + * ========================== + * + * ASTC is a complex format with a large search space. The parts of this search space that are + * searched is determined by heuristics that are, in part, tied to the quality level used when + * creating the context. + * + * A normal context is capable of decompressing any ASTC texture, including those generated by other + * compressors with unknown heuristics. This is the most flexible implementation, but forces the + * data tables used by the codec to include entries that are not needed during compression. This + * can slow down context creation by a significant amount, especially for the faster compression + * modes where few data table entries are actually used. To optimize this use case the context can + * be created with the ASTCENC_FLG_SELF_DECOMPRESS_ONLY flag. This tells the compressor that it will + * only be asked to decompress images that it compressed itself, allowing the data tables to + * exclude entries that are not needed by the current compression configuration. This reduces the + * size of the context data tables in memory and improves context creation performance. Note that, + * as of the 3.6 release, this flag no longer affects compression performance. + * + * Using this flag while attempting to decompress an valid image which was created by another + * compressor, or even another astcenc compressor version or configuration, may result in blocks + * returning as solid magenta or NaN value error blocks. + */ + +#ifndef ASTCENC_INCLUDED +#define ASTCENC_INCLUDED + +#include <cstddef> +#include <cstdint> + +#if defined(ASTCENC_DYNAMIC_LIBRARY) + #if defined(_MSC_VER) + #define ASTCENC_PUBLIC extern "C" __declspec(dllexport) + #else + #define ASTCENC_PUBLIC extern "C" __attribute__ ((visibility ("default"))) + #endif +#else + #define ASTCENC_PUBLIC +#endif + +/* ============================================================================ + Data declarations +============================================================================ */ + +/** + * @brief An opaque structure; see astcenc_internal.h for definition. + */ +struct astcenc_context; + +/** + * @brief A codec API error code. + */ +enum astcenc_error { + /** @brief The call was successful. */ + ASTCENC_SUCCESS = 0, + /** @brief The call failed due to low memory, or undersized I/O buffers. */ + ASTCENC_ERR_OUT_OF_MEM, + /** @brief The call failed due to the build using fast math. */ + ASTCENC_ERR_BAD_CPU_FLOAT, + /** @brief The call failed due to the build using an unsupported ISA. */ + ASTCENC_ERR_BAD_CPU_ISA, + /** @brief The call failed due to an out-of-spec parameter. */ + ASTCENC_ERR_BAD_PARAM, + /** @brief The call failed due to an out-of-spec block size. */ + ASTCENC_ERR_BAD_BLOCK_SIZE, + /** @brief The call failed due to an out-of-spec color profile. */ + ASTCENC_ERR_BAD_PROFILE, + /** @brief The call failed due to an out-of-spec quality value. */ + ASTCENC_ERR_BAD_QUALITY, + /** @brief The call failed due to an out-of-spec component swizzle. */ + ASTCENC_ERR_BAD_SWIZZLE, + /** @brief The call failed due to an out-of-spec flag set. */ + ASTCENC_ERR_BAD_FLAGS, + /** @brief The call failed due to the context not supporting the operation. */ + ASTCENC_ERR_BAD_CONTEXT, + /** @brief The call failed due to unimplemented functionality. */ + ASTCENC_ERR_NOT_IMPLEMENTED, +#if defined(ASTCENC_DIAGNOSTICS) + /** @brief The call failed due to an issue with diagnostic tracing. */ + ASTCENC_ERR_DTRACE_FAILURE, +#endif +}; + +/** + * @brief A codec color profile. + */ +enum astcenc_profile { + /** @brief The LDR sRGB color profile. */ + ASTCENC_PRF_LDR_SRGB = 0, + /** @brief The LDR linear color profile. */ + ASTCENC_PRF_LDR, + /** @brief The HDR RGB with LDR alpha color profile. */ + ASTCENC_PRF_HDR_RGB_LDR_A, + /** @brief The HDR RGBA color profile. */ + ASTCENC_PRF_HDR +}; + +/** @brief The fastest, lowest quality, search preset. */ +static const float ASTCENC_PRE_FASTEST = 0.0f; + +/** @brief The fast search preset. */ +static const float ASTCENC_PRE_FAST = 10.0f; + +/** @brief The medium quality search preset. */ +static const float ASTCENC_PRE_MEDIUM = 60.0f; + +/** @brief The thorough quality search preset. */ +static const float ASTCENC_PRE_THOROUGH = 98.0f; + +/** @brief The thorough quality search preset. */ +static const float ASTCENC_PRE_VERYTHOROUGH = 99.0f; + +/** @brief The exhaustive, highest quality, search preset. */ +static const float ASTCENC_PRE_EXHAUSTIVE = 100.0f; + +/** + * @brief A codec component swizzle selector. + */ +enum astcenc_swz +{ + /** @brief Select the red component. */ + ASTCENC_SWZ_R = 0, + /** @brief Select the green component. */ + ASTCENC_SWZ_G = 1, + /** @brief Select the blue component. */ + ASTCENC_SWZ_B = 2, + /** @brief Select the alpha component. */ + ASTCENC_SWZ_A = 3, + /** @brief Use a constant zero component. */ + ASTCENC_SWZ_0 = 4, + /** @brief Use a constant one component. */ + ASTCENC_SWZ_1 = 5, + /** @brief Use a reconstructed normal vector Z component. */ + ASTCENC_SWZ_Z = 6 +}; + +/** + * @brief A texel component swizzle. + */ +struct astcenc_swizzle +{ + /** @brief The red component selector. */ + astcenc_swz r; + /** @brief The green component selector. */ + astcenc_swz g; + /** @brief The blue component selector. */ + astcenc_swz b; + /** @brief The alpha component selector. */ + astcenc_swz a; +}; + +/** + * @brief A texel component data format. + */ +enum astcenc_type +{ + /** @brief Unorm 8-bit data per component. */ + ASTCENC_TYPE_U8 = 0, + /** @brief 16-bit float per component. */ + ASTCENC_TYPE_F16 = 1, + /** @brief 32-bit float per component. */ + ASTCENC_TYPE_F32 = 2 +}; + +/** + * @brief Enable normal map compression. + * + * Input data will be treated a two component normal map, storing X and Y, and the codec will + * optimize for angular error rather than simple linear PSNR. In this mode the input swizzle should + * be e.g. rrrg (the default ordering for ASTC normals on the command line) or gggr (the ordering + * used by BC5n). + */ +static const unsigned int ASTCENC_FLG_MAP_NORMAL = 1 << 0; + +/** + * @brief Enable alpha weighting. + * + * The input alpha value is used for transparency, so errors in the RGB components are weighted by + * the transparency level. This allows the codec to more accurately encode the alpha value in areas + * where the color value is less significant. + */ +static const unsigned int ASTCENC_FLG_USE_ALPHA_WEIGHT = 1 << 2; + +/** + * @brief Enable perceptual error metrics. + * + * This mode enables perceptual compression mode, which will optimize for perceptual error rather + * than best PSNR. Only some input modes support perceptual error metrics. + */ +static const unsigned int ASTCENC_FLG_USE_PERCEPTUAL = 1 << 3; + +/** + * @brief Create a decompression-only context. + * + * This mode disables support for compression. This enables context allocation to skip some + * transient buffer allocation, resulting in lower memory usage. + */ +static const unsigned int ASTCENC_FLG_DECOMPRESS_ONLY = 1 << 4; + +/** + * @brief Create a self-decompression context. + * + * This mode configures the compressor so that it is only guaranteed to be able to decompress images + * that were actually created using the current context. This is the common case for compression use + * cases, and setting this flag enables additional optimizations, but does mean that the context + * cannot reliably decompress arbitrary ASTC images. + */ +static const unsigned int ASTCENC_FLG_SELF_DECOMPRESS_ONLY = 1 << 5; + +/** + * @brief Enable RGBM map compression. + * + * Input data will be treated as HDR data that has been stored in an LDR RGBM-encoded wrapper + * format. Data must be preprocessed by the user to be in LDR RGBM format before calling the + * compression function, this flag is only used to control the use of RGBM-specific heuristics and + * error metrics. + * + * IMPORTANT: The ASTC format is prone to bad failure modes with unconstrained RGBM data; very small + * M values can round to zero due to quantization and result in black or white pixels. It is highly + * recommended that the minimum value of M used in the encoding is kept above a lower threshold (try + * 16 or 32). Applying this threshold reduces the number of very dark colors that can be + * represented, but is still higher precision than 8-bit LDR. + * + * When this flag is set the value of @c rgbm_m_scale in the context must be set to the RGBM scale + * factor used during reconstruction. This defaults to 5 when in RGBM mode. + * + * It is recommended that the value of @c cw_a_weight is set to twice the value of the multiplier + * scale, ensuring that the M value is accurately encoded. This defaults to 10 when in RGBM mode, + * matching the default scale factor. + */ +static const unsigned int ASTCENC_FLG_MAP_RGBM = 1 << 6; + +/** + * @brief The bit mask of all valid flags. + */ +static const unsigned int ASTCENC_ALL_FLAGS = + ASTCENC_FLG_MAP_NORMAL | + ASTCENC_FLG_MAP_RGBM | + ASTCENC_FLG_USE_ALPHA_WEIGHT | + ASTCENC_FLG_USE_PERCEPTUAL | + ASTCENC_FLG_DECOMPRESS_ONLY | + ASTCENC_FLG_SELF_DECOMPRESS_ONLY; + +/** + * @brief The config structure. + * + * This structure will initially be populated by a call to astcenc_config_init, but power users may + * modify it before calling astcenc_context_alloc. See astcenccli_toplevel_help.cpp for full user + * documentation of the power-user settings. + * + * Note for any settings which are associated with a specific color component, the value in the + * config applies to the component that exists after any compression data swizzle is applied. + */ +struct astcenc_config +{ + /** @brief The color profile. */ + astcenc_profile profile; + + /** @brief The set of set flags. */ + unsigned int flags; + + /** @brief The ASTC block size X dimension. */ + unsigned int block_x; + + /** @brief The ASTC block size Y dimension. */ + unsigned int block_y; + + /** @brief The ASTC block size Z dimension. */ + unsigned int block_z; + + /** @brief The red component weight scale for error weighting (-cw). */ + float cw_r_weight; + + /** @brief The green component weight scale for error weighting (-cw). */ + float cw_g_weight; + + /** @brief The blue component weight scale for error weighting (-cw). */ + float cw_b_weight; + + /** @brief The alpha component weight scale for error weighting (-cw). */ + float cw_a_weight; + + /** + * @brief The radius for any alpha-weight scaling (-a). + * + * It is recommended that this is set to 1 when using FLG_USE_ALPHA_WEIGHT on a texture that + * will be sampled using linear texture filtering to minimize color bleed out of transparent + * texels that are adjacent to non-transparent texels. + */ + unsigned int a_scale_radius; + + /** @brief The RGBM scale factor for the shared multiplier (-rgbm). */ + float rgbm_m_scale; + + /** + * @brief The maximum number of partitions searched (-partitioncountlimit). + * + * Valid values are between 1 and 4. + */ + unsigned int tune_partition_count_limit; + + /** + * @brief The maximum number of partitions searched (-2partitionindexlimit). + * + * Valid values are between 1 and 1024. + */ + unsigned int tune_2partition_index_limit; + + /** + * @brief The maximum number of partitions searched (-3partitionindexlimit). + * + * Valid values are between 1 and 1024. + */ + unsigned int tune_3partition_index_limit; + + /** + * @brief The maximum number of partitions searched (-4partitionindexlimit). + * + * Valid values are between 1 and 1024. + */ + unsigned int tune_4partition_index_limit; + + /** + * @brief The maximum centile for block modes searched (-blockmodelimit). + * + * Valid values are between 1 and 100. + */ + unsigned int tune_block_mode_limit; + + /** + * @brief The maximum iterative refinements applied (-refinementlimit). + * + * Valid values are between 1 and N; there is no technical upper limit + * but little benefit is expected after N=4. + */ + unsigned int tune_refinement_limit; + + /** + * @brief The number of trial candidates per mode search (-candidatelimit). + * + * Valid values are between 1 and TUNE_MAX_TRIAL_CANDIDATES (default 4). + */ + unsigned int tune_candidate_limit; + + /** + * @brief The number of trial partitionings per search (-2partitioncandidatelimit). + * + * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES. + */ + unsigned int tune_2partitioning_candidate_limit; + + /** + * @brief The number of trial partitionings per search (-3partitioncandidatelimit). + * + * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES. + */ + unsigned int tune_3partitioning_candidate_limit; + + /** + * @brief The number of trial partitionings per search (-4partitioncandidatelimit). + * + * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES. + */ + unsigned int tune_4partitioning_candidate_limit; + + /** + * @brief The dB threshold for stopping block search (-dblimit). + * + * This option is ineffective for HDR textures. + */ + float tune_db_limit; + + /** + * @brief The amount of MSE overshoot needed to early-out trials. + * + * The first early-out is for 1 partition, 1 plane trials, where we try a minimal encode using + * the high probability block modes. This can short-cut compression for simple blocks. + * + * The second early-out is for refinement trials, where we can exit refinement once quality is + * reached. + */ + float tune_mse_overshoot; + + /** + * @brief The threshold for skipping 3.1/4.1 trials (-2partitionlimitfactor). + * + * This option is further scaled for normal maps, so it skips less often. + */ + float tune_2_partition_early_out_limit_factor; + + /** + * @brief The threshold for skipping 4.1 trials (-3partitionlimitfactor). + * + * This option is further scaled for normal maps, so it skips less often. + */ + float tune_3_partition_early_out_limit_factor; + + /** + * @brief The threshold for skipping two weight planes (-2planelimitcorrelation). + * + * This option is ineffective for normal maps. + */ + float tune_2_plane_early_out_limit_correlation; + +#if defined(ASTCENC_DIAGNOSTICS) + /** + * @brief The path to save the diagnostic trace data to. + * + * This option is not part of the public API, and requires special builds + * of the library. + */ + const char* trace_file_path; +#endif +}; + +/** + * @brief An uncompressed 2D or 3D image. + * + * 3D image are passed in as an array of 2D slices. Each slice has identical + * size and color format. + */ +struct astcenc_image +{ + /** @brief The X dimension of the image, in texels. */ + unsigned int dim_x; + + /** @brief The Y dimension of the image, in texels. */ + unsigned int dim_y; + + /** @brief The Z dimension of the image, in texels. */ + unsigned int dim_z; + + /** @brief The data type per component. */ + astcenc_type data_type; + + /** @brief The array of 2D slices, of length @c dim_z. */ + void** data; +}; + +/** + * @brief A block encoding metadata query result. + * + * If the block is an error block or a constant color block or an error block all fields other than + * the profile, block dimensions, and error/constant indicator will be zero. + */ +struct astcenc_block_info +{ + /** @brief The block encoding color profile. */ + astcenc_profile profile; + + /** @brief The number of texels in the X dimension. */ + unsigned int block_x; + + /** @brief The number of texels in the Y dimension. */ + unsigned int block_y; + + /** @brief The number of texel in the Z dimension. */ + unsigned int block_z; + + /** @brief The number of texels in the block. */ + unsigned int texel_count; + + /** @brief True if this block is an error block. */ + bool is_error_block; + + /** @brief True if this block is a constant color block. */ + bool is_constant_block; + + /** @brief True if this block is an HDR block. */ + bool is_hdr_block; + + /** @brief True if this block uses two weight planes. */ + bool is_dual_plane_block; + + /** @brief The number of partitions if not constant color. */ + unsigned int partition_count; + + /** @brief The partition index if 2 - 4 partitions used. */ + unsigned int partition_index; + + /** @brief The component index of the second plane if dual plane. */ + unsigned int dual_plane_component; + + /** @brief The color endpoint encoding mode for each partition. */ + unsigned int color_endpoint_modes[4]; + + /** @brief The number of color endpoint quantization levels. */ + unsigned int color_level_count; + + /** @brief The number of weight quantization levels. */ + unsigned int weight_level_count; + + /** @brief The number of weights in the X dimension. */ + unsigned int weight_x; + + /** @brief The number of weights in the Y dimension. */ + unsigned int weight_y; + + /** @brief The number of weights in the Z dimension. */ + unsigned int weight_z; + + /** @brief The unpacked color endpoints for each partition. */ + float color_endpoints[4][2][4]; + + /** @brief The per-texel interpolation weights for the block. */ + float weight_values_plane1[216]; + + /** @brief The per-texel interpolation weights for the block. */ + float weight_values_plane2[216]; + + /** @brief The per-texel partition assignments for the block. */ + uint8_t partition_assignment[216]; +}; + +/** + * Populate a codec config based on default settings. + * + * Power users can edit the returned config struct to fine tune before allocating the context. + * + * @param profile Color profile. + * @param block_x ASTC block size X dimension. + * @param block_y ASTC block size Y dimension. + * @param block_z ASTC block size Z dimension. + * @param quality Search quality preset / effort level. Either an + * @c ASTCENC_PRE_* value, or a effort level between 0 + * and 100. Performance is not linear between 0 and 100. + + * @param flags A valid set of @c ASTCENC_FLG_* flag bits. + * @param[out] config Output config struct to populate. + * + * @return @c ASTCENC_SUCCESS on success, or an error if the inputs are invalid + * either individually, or in combination. + */ +ASTCENC_PUBLIC astcenc_error astcenc_config_init( + astcenc_profile profile, + unsigned int block_x, + unsigned int block_y, + unsigned int block_z, + float quality, + unsigned int flags, + astcenc_config* config); + +/** + * @brief Allocate a new codec context based on a config. + * + * This function allocates all of the memory resources and threads needed by the codec. This can be + * slow, so it is recommended that contexts are reused to serially compress or decompress multiple + * images to amortize setup cost. + * + * Contexts can be allocated to support only decompression using the @c ASTCENC_FLG_DECOMPRESS_ONLY + * flag when creating the configuration. The compression functions will fail if invoked. For a + * decompress-only library build the @c ASTCENC_FLG_DECOMPRESS_ONLY flag must be set when creating + * any context. + * + * @param[in] config Codec config. + * @param thread_count Thread count to configure for. + * @param[out] context Location to store an opaque context pointer. + * + * @return @c ASTCENC_SUCCESS on success, or an error if context creation failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_context_alloc( + const astcenc_config* config, + unsigned int thread_count, + astcenc_context** context); + +/** + * @brief Compress an image. + * + * A single context can only compress or decompress a single image at a time. + * + * For a context configured for multi-threading, any set of the N threads can call this function. + * Work will be dynamically scheduled across the threads available. Each thread must have a unique + * @c thread_index. + * + * @param context Codec context. + * @param[in,out] image An input image, in 2D slices. + * @param swizzle Compression data swizzle, applied before compression. + * @param[out] data_out Pointer to output data array. + * @param data_len Length of the output data array. + * @param thread_index Thread index [0..N-1] of calling thread. + * + * @return @c ASTCENC_SUCCESS on success, or an error if compression failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_compress_image( + astcenc_context* context, + astcenc_image* image, + const astcenc_swizzle* swizzle, + uint8_t* data_out, + size_t data_len, + unsigned int thread_index); + +/** + * @brief Reset the codec state for a new compression. + * + * The caller is responsible for synchronizing threads in the worker thread pool. This function must + * only be called when all threads have exited the @c astcenc_compress_image() function for image N, + * but before any thread enters it for image N + 1. + * + * Calling this is not required (but won't hurt), if the context is created for single threaded use. + * + * @param context Codec context. + * + * @return @c ASTCENC_SUCCESS on success, or an error if reset failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_compress_reset( + astcenc_context* context); + +/** + * @brief Decompress an image. + * + * @param context Codec context. + * @param[in] data Pointer to compressed data. + * @param data_len Length of the compressed data, in bytes. + * @param[in,out] image_out Output image. + * @param swizzle Decompression data swizzle, applied after decompression. + * @param thread_index Thread index [0..N-1] of calling thread. + * + * @return @c ASTCENC_SUCCESS on success, or an error if decompression failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_decompress_image( + astcenc_context* context, + const uint8_t* data, + size_t data_len, + astcenc_image* image_out, + const astcenc_swizzle* swizzle, + unsigned int thread_index); + +/** + * @brief Reset the codec state for a new decompression. + * + * The caller is responsible for synchronizing threads in the worker thread pool. This function must + * only be called when all threads have exited the @c astcenc_decompress_image() function for image + * N, but before any thread enters it for image N + 1. + * + * Calling this is not required (but won't hurt), if the context is created for single threaded use. + * + * @param context Codec context. + * + * @return @c ASTCENC_SUCCESS on success, or an error if reset failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_decompress_reset( + astcenc_context* context); + +/** + * Free the compressor context. + * + * @param context The codec context. + */ +ASTCENC_PUBLIC void astcenc_context_free( + astcenc_context* context); + +/** + * @brief Provide a high level summary of a block's encoding. + * + * This feature is primarily useful for codec developers but may be useful for developers building + * advanced content packaging pipelines. + * + * @param context Codec context. + * @param data One block of compressed ASTC data. + * @param info The output info structure to populate. + * + * @return @c ASTCENC_SUCCESS if the block was decoded, or an error otherwise. Note that this + * function will return success even if the block itself was an error block encoding, as the + * decode was correctly handled. + */ +ASTCENC_PUBLIC astcenc_error astcenc_get_block_info( + astcenc_context* context, + const uint8_t data[16], + astcenc_block_info* info); + +/** + * @brief Get a printable string for specific status code. + * + * @param status The status value. + * + * @return A human readable nul-terminated string. + */ +ASTCENC_PUBLIC const char* astcenc_get_error_string( + astcenc_error status); + +#endif diff --git a/thirdparty/astcenc/astcenc_averages_and_directions.cpp b/thirdparty/astcenc/astcenc_averages_and_directions.cpp new file mode 100644 index 0000000000..d1f003844a --- /dev/null +++ b/thirdparty/astcenc/astcenc_averages_and_directions.cpp @@ -0,0 +1,995 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for finding dominant direction of a set of colors. + */ +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +#include "astcenc_internal.h" + +#include <cassert> + +/** + * @brief Compute the average RGB color of each partition. + * + * The algorithm here uses a vectorized sequential scan and per-partition + * color accumulators, using select() to mask texel lanes in other partitions. + * + * We only accumulate sums for N-1 partitions during the scan; the value for + * the last partition can be computed given that we know the block-wide average + * already. + * + * Because of this we could reduce the loop iteration count so it "just" spans + * the max texel index needed for the N-1 partitions, which could need fewer + * iterations than the full block texel count. However, this makes the loop + * count erratic and causes more branch mispredictions so is a net loss. + * + * @param pi The partitioning to use. + * @param blk The block data to process. + * @param[out] averages The output averages. Unused partition indices will + * not be initialized, and lane<3> will be zero. + */ +static void compute_partition_averages_rgb( + const partition_info& pi, + const image_block& blk, + vfloat4 averages[BLOCK_MAX_PARTITIONS] +) { + unsigned int partition_count = pi.partition_count; + unsigned int texel_count = blk.texel_count; + promise(texel_count > 0); + + // For 1 partition just use the precomputed mean + if (partition_count == 1) + { + averages[0] = blk.data_mean.swz<0, 1, 2>(); + } + // For 2 partitions scan results for partition 0, compute partition 1 + else if (partition_count == 2) + { + vfloatacc pp_avg_rgb[3] {}; + + vint lane_id = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint texel_partition(pi.partition_of_texel + i); + + vmask lane_mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + + vmask p0_mask = lane_mask & (texel_partition == vint(0)); + + vfloat data_r = loada(blk.data_r + i); + haccumulate(pp_avg_rgb[0], data_r, p0_mask); + + vfloat data_g = loada(blk.data_g + i); + haccumulate(pp_avg_rgb[1], data_g, p0_mask); + + vfloat data_b = loada(blk.data_b + i); + haccumulate(pp_avg_rgb[2], data_b, p0_mask); + } + + vfloat4 block_total = blk.data_mean.swz<0, 1, 2>() * static_cast<float>(blk.texel_count); + + vfloat4 p0_total = vfloat3(hadd_s(pp_avg_rgb[0]), + hadd_s(pp_avg_rgb[1]), + hadd_s(pp_avg_rgb[2])); + + vfloat4 p1_total = block_total - p0_total; + + averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]); + averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]); + } + // For 3 partitions scan results for partition 0/1, compute partition 2 + else if (partition_count == 3) + { + vfloatacc pp_avg_rgb[2][3] {}; + + vint lane_id = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint texel_partition(pi.partition_of_texel + i); + + vmask lane_mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + + vmask p0_mask = lane_mask & (texel_partition == vint(0)); + vmask p1_mask = lane_mask & (texel_partition == vint(1)); + + vfloat data_r = loada(blk.data_r + i); + haccumulate(pp_avg_rgb[0][0], data_r, p0_mask); + haccumulate(pp_avg_rgb[1][0], data_r, p1_mask); + + vfloat data_g = loada(blk.data_g + i); + haccumulate(pp_avg_rgb[0][1], data_g, p0_mask); + haccumulate(pp_avg_rgb[1][1], data_g, p1_mask); + + vfloat data_b = loada(blk.data_b + i); + haccumulate(pp_avg_rgb[0][2], data_b, p0_mask); + haccumulate(pp_avg_rgb[1][2], data_b, p1_mask); + } + + vfloat4 block_total = blk.data_mean.swz<0, 1, 2>() * static_cast<float>(blk.texel_count); + + vfloat4 p0_total = vfloat3(hadd_s(pp_avg_rgb[0][0]), + hadd_s(pp_avg_rgb[0][1]), + hadd_s(pp_avg_rgb[0][2])); + + vfloat4 p1_total = vfloat3(hadd_s(pp_avg_rgb[1][0]), + hadd_s(pp_avg_rgb[1][1]), + hadd_s(pp_avg_rgb[1][2])); + + vfloat4 p2_total = block_total - p0_total - p1_total; + + averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]); + averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]); + averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]); + } + else + { + // For 4 partitions scan results for partition 0/1/2, compute partition 3 + vfloatacc pp_avg_rgb[3][3] {}; + + vint lane_id = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint texel_partition(pi.partition_of_texel + i); + + vmask lane_mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + + vmask p0_mask = lane_mask & (texel_partition == vint(0)); + vmask p1_mask = lane_mask & (texel_partition == vint(1)); + vmask p2_mask = lane_mask & (texel_partition == vint(2)); + + vfloat data_r = loada(blk.data_r + i); + haccumulate(pp_avg_rgb[0][0], data_r, p0_mask); + haccumulate(pp_avg_rgb[1][0], data_r, p1_mask); + haccumulate(pp_avg_rgb[2][0], data_r, p2_mask); + + vfloat data_g = loada(blk.data_g + i); + haccumulate(pp_avg_rgb[0][1], data_g, p0_mask); + haccumulate(pp_avg_rgb[1][1], data_g, p1_mask); + haccumulate(pp_avg_rgb[2][1], data_g, p2_mask); + + vfloat data_b = loada(blk.data_b + i); + haccumulate(pp_avg_rgb[0][2], data_b, p0_mask); + haccumulate(pp_avg_rgb[1][2], data_b, p1_mask); + haccumulate(pp_avg_rgb[2][2], data_b, p2_mask); + } + + vfloat4 block_total = blk.data_mean.swz<0, 1, 2>() * static_cast<float>(blk.texel_count); + + vfloat4 p0_total = vfloat3(hadd_s(pp_avg_rgb[0][0]), + hadd_s(pp_avg_rgb[0][1]), + hadd_s(pp_avg_rgb[0][2])); + + vfloat4 p1_total = vfloat3(hadd_s(pp_avg_rgb[1][0]), + hadd_s(pp_avg_rgb[1][1]), + hadd_s(pp_avg_rgb[1][2])); + + vfloat4 p2_total = vfloat3(hadd_s(pp_avg_rgb[2][0]), + hadd_s(pp_avg_rgb[2][1]), + hadd_s(pp_avg_rgb[2][2])); + + vfloat4 p3_total = block_total - p0_total - p1_total- p2_total; + + averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]); + averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]); + averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]); + averages[3] = p3_total / static_cast<float>(pi.partition_texel_count[3]); + } +} + +/** + * @brief Compute the average RGBA color of each partition. + * + * The algorithm here uses a vectorized sequential scan and per-partition + * color accumulators, using select() to mask texel lanes in other partitions. + * + * We only accumulate sums for N-1 partitions during the scan; the value for + * the last partition can be computed given that we know the block-wide average + * already. + * + * Because of this we could reduce the loop iteration count so it "just" spans + * the max texel index needed for the N-1 partitions, which could need fewer + * iterations than the full block texel count. However, this makes the loop + * count erratic and causes more branch mispredictions so is a net loss. + * + * @param pi The partitioning to use. + * @param blk The block data to process. + * @param[out] averages The output averages. Unused partition indices will + * not be initialized. + */ +static void compute_partition_averages_rgba( + const partition_info& pi, + const image_block& blk, + vfloat4 averages[BLOCK_MAX_PARTITIONS] +) { + unsigned int partition_count = pi.partition_count; + unsigned int texel_count = blk.texel_count; + promise(texel_count > 0); + + // For 1 partition just use the precomputed mean + if (partition_count == 1) + { + averages[0] = blk.data_mean; + } + // For 2 partitions scan results for partition 0, compute partition 1 + else if (partition_count == 2) + { + vfloat4 pp_avg_rgba[4] {}; + + vint lane_id = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint texel_partition(pi.partition_of_texel + i); + + vmask lane_mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + + vmask p0_mask = lane_mask & (texel_partition == vint(0)); + + vfloat data_r = loada(blk.data_r + i); + haccumulate(pp_avg_rgba[0], data_r, p0_mask); + + vfloat data_g = loada(blk.data_g + i); + haccumulate(pp_avg_rgba[1], data_g, p0_mask); + + vfloat data_b = loada(blk.data_b + i); + haccumulate(pp_avg_rgba[2], data_b, p0_mask); + + vfloat data_a = loada(blk.data_a + i); + haccumulate(pp_avg_rgba[3], data_a, p0_mask); + } + + vfloat4 block_total = blk.data_mean * static_cast<float>(blk.texel_count); + + vfloat4 p0_total = vfloat4(hadd_s(pp_avg_rgba[0]), + hadd_s(pp_avg_rgba[1]), + hadd_s(pp_avg_rgba[2]), + hadd_s(pp_avg_rgba[3])); + + vfloat4 p1_total = block_total - p0_total; + + averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]); + averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]); + } + // For 3 partitions scan results for partition 0/1, compute partition 2 + else if (partition_count == 3) + { + vfloat4 pp_avg_rgba[2][4] {}; + + vint lane_id = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint texel_partition(pi.partition_of_texel + i); + + vmask lane_mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + + vmask p0_mask = lane_mask & (texel_partition == vint(0)); + vmask p1_mask = lane_mask & (texel_partition == vint(1)); + + vfloat data_r = loada(blk.data_r + i); + haccumulate(pp_avg_rgba[0][0], data_r, p0_mask); + haccumulate(pp_avg_rgba[1][0], data_r, p1_mask); + + vfloat data_g = loada(blk.data_g + i); + haccumulate(pp_avg_rgba[0][1], data_g, p0_mask); + haccumulate(pp_avg_rgba[1][1], data_g, p1_mask); + + vfloat data_b = loada(blk.data_b + i); + haccumulate(pp_avg_rgba[0][2], data_b, p0_mask); + haccumulate(pp_avg_rgba[1][2], data_b, p1_mask); + + vfloat data_a = loada(blk.data_a + i); + haccumulate(pp_avg_rgba[0][3], data_a, p0_mask); + haccumulate(pp_avg_rgba[1][3], data_a, p1_mask); + } + + vfloat4 block_total = blk.data_mean * static_cast<float>(blk.texel_count); + + vfloat4 p0_total = vfloat4(hadd_s(pp_avg_rgba[0][0]), + hadd_s(pp_avg_rgba[0][1]), + hadd_s(pp_avg_rgba[0][2]), + hadd_s(pp_avg_rgba[0][3])); + + vfloat4 p1_total = vfloat4(hadd_s(pp_avg_rgba[1][0]), + hadd_s(pp_avg_rgba[1][1]), + hadd_s(pp_avg_rgba[1][2]), + hadd_s(pp_avg_rgba[1][3])); + + vfloat4 p2_total = block_total - p0_total - p1_total; + + averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]); + averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]); + averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]); + } + else + { + // For 4 partitions scan results for partition 0/1/2, compute partition 3 + vfloat4 pp_avg_rgba[3][4] {}; + + vint lane_id = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint texel_partition(pi.partition_of_texel + i); + + vmask lane_mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + + vmask p0_mask = lane_mask & (texel_partition == vint(0)); + vmask p1_mask = lane_mask & (texel_partition == vint(1)); + vmask p2_mask = lane_mask & (texel_partition == vint(2)); + + vfloat data_r = loada(blk.data_r + i); + haccumulate(pp_avg_rgba[0][0], data_r, p0_mask); + haccumulate(pp_avg_rgba[1][0], data_r, p1_mask); + haccumulate(pp_avg_rgba[2][0], data_r, p2_mask); + + vfloat data_g = loada(blk.data_g + i); + haccumulate(pp_avg_rgba[0][1], data_g, p0_mask); + haccumulate(pp_avg_rgba[1][1], data_g, p1_mask); + haccumulate(pp_avg_rgba[2][1], data_g, p2_mask); + + vfloat data_b = loada(blk.data_b + i); + haccumulate(pp_avg_rgba[0][2], data_b, p0_mask); + haccumulate(pp_avg_rgba[1][2], data_b, p1_mask); + haccumulate(pp_avg_rgba[2][2], data_b, p2_mask); + + vfloat data_a = loada(blk.data_a + i); + haccumulate(pp_avg_rgba[0][3], data_a, p0_mask); + haccumulate(pp_avg_rgba[1][3], data_a, p1_mask); + haccumulate(pp_avg_rgba[2][3], data_a, p2_mask); + } + + vfloat4 block_total = blk.data_mean * static_cast<float>(blk.texel_count); + + vfloat4 p0_total = vfloat4(hadd_s(pp_avg_rgba[0][0]), + hadd_s(pp_avg_rgba[0][1]), + hadd_s(pp_avg_rgba[0][2]), + hadd_s(pp_avg_rgba[0][3])); + + vfloat4 p1_total = vfloat4(hadd_s(pp_avg_rgba[1][0]), + hadd_s(pp_avg_rgba[1][1]), + hadd_s(pp_avg_rgba[1][2]), + hadd_s(pp_avg_rgba[1][3])); + + vfloat4 p2_total = vfloat4(hadd_s(pp_avg_rgba[2][0]), + hadd_s(pp_avg_rgba[2][1]), + hadd_s(pp_avg_rgba[2][2]), + hadd_s(pp_avg_rgba[2][3])); + + vfloat4 p3_total = block_total - p0_total - p1_total- p2_total; + + averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]); + averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]); + averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]); + averages[3] = p3_total / static_cast<float>(pi.partition_texel_count[3]); + } +} + +/* See header for documentation. */ +void compute_avgs_and_dirs_4_comp( + const partition_info& pi, + const image_block& blk, + partition_metrics pm[BLOCK_MAX_PARTITIONS] +) { + int partition_count = pi.partition_count; + promise(partition_count > 0); + + // Pre-compute partition_averages + vfloat4 partition_averages[BLOCK_MAX_PARTITIONS]; + compute_partition_averages_rgba(pi, blk, partition_averages); + + for (int partition = 0; partition < partition_count; partition++) + { + const uint8_t *texel_indexes = pi.texels_of_partition[partition]; + unsigned int texel_count = pi.partition_texel_count[partition]; + promise(texel_count > 0); + + vfloat4 average = partition_averages[partition]; + pm[partition].avg = average; + + vfloat4 sum_xp = vfloat4::zero(); + vfloat4 sum_yp = vfloat4::zero(); + vfloat4 sum_zp = vfloat4::zero(); + vfloat4 sum_wp = vfloat4::zero(); + + for (unsigned int i = 0; i < texel_count; i++) + { + unsigned int iwt = texel_indexes[i]; + vfloat4 texel_datum = blk.texel(iwt); + texel_datum = texel_datum - average; + + vfloat4 zero = vfloat4::zero(); + + vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero; + sum_xp += select(zero, texel_datum, tdm0); + + vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero; + sum_yp += select(zero, texel_datum, tdm1); + + vmask4 tdm2 = texel_datum.swz<2,2,2,2>() > zero; + sum_zp += select(zero, texel_datum, tdm2); + + vmask4 tdm3 = texel_datum.swz<3,3,3,3>() > zero; + sum_wp += select(zero, texel_datum, tdm3); + } + + vfloat4 prod_xp = dot(sum_xp, sum_xp); + vfloat4 prod_yp = dot(sum_yp, sum_yp); + vfloat4 prod_zp = dot(sum_zp, sum_zp); + vfloat4 prod_wp = dot(sum_wp, sum_wp); + + vfloat4 best_vector = sum_xp; + vfloat4 best_sum = prod_xp; + + vmask4 mask = prod_yp > best_sum; + best_vector = select(best_vector, sum_yp, mask); + best_sum = select(best_sum, prod_yp, mask); + + mask = prod_zp > best_sum; + best_vector = select(best_vector, sum_zp, mask); + best_sum = select(best_sum, prod_zp, mask); + + mask = prod_wp > best_sum; + best_vector = select(best_vector, sum_wp, mask); + + pm[partition].dir = best_vector; + } +} + +/* See header for documentation. */ +void compute_avgs_and_dirs_3_comp( + const partition_info& pi, + const image_block& blk, + unsigned int omitted_component, + partition_metrics pm[BLOCK_MAX_PARTITIONS] +) { + // Pre-compute partition_averages + vfloat4 partition_averages[BLOCK_MAX_PARTITIONS]; + compute_partition_averages_rgba(pi, blk, partition_averages); + + const float* data_vr = blk.data_r; + const float* data_vg = blk.data_g; + const float* data_vb = blk.data_b; + + // TODO: Data-driven permute would be useful to avoid this ... + if (omitted_component == 0) + { + partition_averages[0] = partition_averages[0].swz<1, 2, 3>(); + partition_averages[1] = partition_averages[1].swz<1, 2, 3>(); + partition_averages[2] = partition_averages[2].swz<1, 2, 3>(); + partition_averages[3] = partition_averages[3].swz<1, 2, 3>(); + + data_vr = blk.data_g; + data_vg = blk.data_b; + data_vb = blk.data_a; + } + else if (omitted_component == 1) + { + partition_averages[0] = partition_averages[0].swz<0, 2, 3>(); + partition_averages[1] = partition_averages[1].swz<0, 2, 3>(); + partition_averages[2] = partition_averages[2].swz<0, 2, 3>(); + partition_averages[3] = partition_averages[3].swz<0, 2, 3>(); + + data_vg = blk.data_b; + data_vb = blk.data_a; + } + else if (omitted_component == 2) + { + partition_averages[0] = partition_averages[0].swz<0, 1, 3>(); + partition_averages[1] = partition_averages[1].swz<0, 1, 3>(); + partition_averages[2] = partition_averages[2].swz<0, 1, 3>(); + partition_averages[3] = partition_averages[3].swz<0, 1, 3>(); + + data_vb = blk.data_a; + } + else + { + partition_averages[0] = partition_averages[0].swz<0, 1, 2>(); + partition_averages[1] = partition_averages[1].swz<0, 1, 2>(); + partition_averages[2] = partition_averages[2].swz<0, 1, 2>(); + partition_averages[3] = partition_averages[3].swz<0, 1, 2>(); + } + + unsigned int partition_count = pi.partition_count; + promise(partition_count > 0); + + for (unsigned int partition = 0; partition < partition_count; partition++) + { + const uint8_t *texel_indexes = pi.texels_of_partition[partition]; + unsigned int texel_count = pi.partition_texel_count[partition]; + promise(texel_count > 0); + + vfloat4 average = partition_averages[partition]; + pm[partition].avg = average; + + vfloat4 sum_xp = vfloat4::zero(); + vfloat4 sum_yp = vfloat4::zero(); + vfloat4 sum_zp = vfloat4::zero(); + + for (unsigned int i = 0; i < texel_count; i++) + { + unsigned int iwt = texel_indexes[i]; + + vfloat4 texel_datum = vfloat3(data_vr[iwt], + data_vg[iwt], + data_vb[iwt]); + texel_datum = texel_datum - average; + + vfloat4 zero = vfloat4::zero(); + + vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero; + sum_xp += select(zero, texel_datum, tdm0); + + vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero; + sum_yp += select(zero, texel_datum, tdm1); + + vmask4 tdm2 = texel_datum.swz<2,2,2,2>() > zero; + sum_zp += select(zero, texel_datum, tdm2); + } + + vfloat4 prod_xp = dot(sum_xp, sum_xp); + vfloat4 prod_yp = dot(sum_yp, sum_yp); + vfloat4 prod_zp = dot(sum_zp, sum_zp); + + vfloat4 best_vector = sum_xp; + vfloat4 best_sum = prod_xp; + + vmask4 mask = prod_yp > best_sum; + best_vector = select(best_vector, sum_yp, mask); + best_sum = select(best_sum, prod_yp, mask); + + mask = prod_zp > best_sum; + best_vector = select(best_vector, sum_zp, mask); + + pm[partition].dir = best_vector; + } +} + +/* See header for documentation. */ +void compute_avgs_and_dirs_3_comp_rgb( + const partition_info& pi, + const image_block& blk, + partition_metrics pm[BLOCK_MAX_PARTITIONS] +) { + unsigned int partition_count = pi.partition_count; + promise(partition_count > 0); + + // Pre-compute partition_averages + vfloat4 partition_averages[BLOCK_MAX_PARTITIONS]; + compute_partition_averages_rgb(pi, blk, partition_averages); + + for (unsigned int partition = 0; partition < partition_count; partition++) + { + const uint8_t *texel_indexes = pi.texels_of_partition[partition]; + unsigned int texel_count = pi.partition_texel_count[partition]; + promise(texel_count > 0); + + vfloat4 average = partition_averages[partition]; + pm[partition].avg = average; + + vfloat4 sum_xp = vfloat4::zero(); + vfloat4 sum_yp = vfloat4::zero(); + vfloat4 sum_zp = vfloat4::zero(); + + for (unsigned int i = 0; i < texel_count; i++) + { + unsigned int iwt = texel_indexes[i]; + + vfloat4 texel_datum = blk.texel3(iwt); + texel_datum = texel_datum - average; + + vfloat4 zero = vfloat4::zero(); + + vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero; + sum_xp += select(zero, texel_datum, tdm0); + + vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero; + sum_yp += select(zero, texel_datum, tdm1); + + vmask4 tdm2 = texel_datum.swz<2,2,2,2>() > zero; + sum_zp += select(zero, texel_datum, tdm2); + } + + vfloat4 prod_xp = dot(sum_xp, sum_xp); + vfloat4 prod_yp = dot(sum_yp, sum_yp); + vfloat4 prod_zp = dot(sum_zp, sum_zp); + + vfloat4 best_vector = sum_xp; + vfloat4 best_sum = prod_xp; + + vmask4 mask = prod_yp > best_sum; + best_vector = select(best_vector, sum_yp, mask); + best_sum = select(best_sum, prod_yp, mask); + + mask = prod_zp > best_sum; + best_vector = select(best_vector, sum_zp, mask); + + pm[partition].dir = best_vector; + } +} + +/* See header for documentation. */ +void compute_avgs_and_dirs_2_comp( + const partition_info& pt, + const image_block& blk, + unsigned int component1, + unsigned int component2, + partition_metrics pm[BLOCK_MAX_PARTITIONS] +) { + vfloat4 average; + + const float* data_vr = nullptr; + const float* data_vg = nullptr; + + if (component1 == 0 && component2 == 1) + { + average = blk.data_mean.swz<0, 1>(); + + data_vr = blk.data_r; + data_vg = blk.data_g; + } + else if (component1 == 0 && component2 == 2) + { + average = blk.data_mean.swz<0, 2>(); + + data_vr = blk.data_r; + data_vg = blk.data_b; + } + else // (component1 == 1 && component2 == 2) + { + assert(component1 == 1 && component2 == 2); + + average = blk.data_mean.swz<1, 2>(); + + data_vr = blk.data_g; + data_vg = blk.data_b; + } + + unsigned int partition_count = pt.partition_count; + promise(partition_count > 0); + + for (unsigned int partition = 0; partition < partition_count; partition++) + { + const uint8_t *texel_indexes = pt.texels_of_partition[partition]; + unsigned int texel_count = pt.partition_texel_count[partition]; + promise(texel_count > 0); + + // Only compute a partition mean if more than one partition + if (partition_count > 1) + { + average = vfloat4::zero(); + for (unsigned int i = 0; i < texel_count; i++) + { + unsigned int iwt = texel_indexes[i]; + average += vfloat2(data_vr[iwt], data_vg[iwt]); + } + + average = average / static_cast<float>(texel_count); + } + + pm[partition].avg = average; + + vfloat4 sum_xp = vfloat4::zero(); + vfloat4 sum_yp = vfloat4::zero(); + + for (unsigned int i = 0; i < texel_count; i++) + { + unsigned int iwt = texel_indexes[i]; + vfloat4 texel_datum = vfloat2(data_vr[iwt], data_vg[iwt]); + texel_datum = texel_datum - average; + + vfloat4 zero = vfloat4::zero(); + + vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero; + sum_xp += select(zero, texel_datum, tdm0); + + vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero; + sum_yp += select(zero, texel_datum, tdm1); + } + + vfloat4 prod_xp = dot(sum_xp, sum_xp); + vfloat4 prod_yp = dot(sum_yp, sum_yp); + + vfloat4 best_vector = sum_xp; + vfloat4 best_sum = prod_xp; + + vmask4 mask = prod_yp > best_sum; + best_vector = select(best_vector, sum_yp, mask); + + pm[partition].dir = best_vector; + } +} + +/* See header for documentation. */ +void compute_error_squared_rgba( + const partition_info& pi, + const image_block& blk, + const processed_line4 uncor_plines[BLOCK_MAX_PARTITIONS], + const processed_line4 samec_plines[BLOCK_MAX_PARTITIONS], + float uncor_lengths[BLOCK_MAX_PARTITIONS], + float samec_lengths[BLOCK_MAX_PARTITIONS], + float& uncor_error, + float& samec_error +) { + unsigned int partition_count = pi.partition_count; + promise(partition_count > 0); + + vfloatacc uncor_errorsumv = vfloatacc::zero(); + vfloatacc samec_errorsumv = vfloatacc::zero(); + + for (unsigned int partition = 0; partition < partition_count; partition++) + { + const uint8_t *texel_indexes = pi.texels_of_partition[partition]; + + float uncor_loparam = 1e10f; + float uncor_hiparam = -1e10f; + + float samec_loparam = 1e10f; + float samec_hiparam = -1e10f; + + processed_line4 l_uncor = uncor_plines[partition]; + processed_line4 l_samec = samec_plines[partition]; + + unsigned int texel_count = pi.partition_texel_count[partition]; + promise(texel_count > 0); + + // Vectorize some useful scalar inputs + vfloat l_uncor_bs0(l_uncor.bs.lane<0>()); + vfloat l_uncor_bs1(l_uncor.bs.lane<1>()); + vfloat l_uncor_bs2(l_uncor.bs.lane<2>()); + vfloat l_uncor_bs3(l_uncor.bs.lane<3>()); + + vfloat l_uncor_amod0(l_uncor.amod.lane<0>()); + vfloat l_uncor_amod1(l_uncor.amod.lane<1>()); + vfloat l_uncor_amod2(l_uncor.amod.lane<2>()); + vfloat l_uncor_amod3(l_uncor.amod.lane<3>()); + + vfloat l_samec_bs0(l_samec.bs.lane<0>()); + vfloat l_samec_bs1(l_samec.bs.lane<1>()); + vfloat l_samec_bs2(l_samec.bs.lane<2>()); + vfloat l_samec_bs3(l_samec.bs.lane<3>()); + + assert(all(l_samec.amod == vfloat4(0.0f))); + + vfloat uncor_loparamv(1e10f); + vfloat uncor_hiparamv(-1e10f); + + vfloat samec_loparamv(1e10f); + vfloat samec_hiparamv(-1e10f); + + vfloat ew_r(blk.channel_weight.lane<0>()); + vfloat ew_g(blk.channel_weight.lane<1>()); + vfloat ew_b(blk.channel_weight.lane<2>()); + vfloat ew_a(blk.channel_weight.lane<3>()); + + // This implementation over-shoots, but this is safe as we initialize the texel_indexes + // array to extend the last value. This means min/max are not impacted, but we need to mask + // out the dummy values when we compute the line weighting. + vint lane_ids = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vmask mask = lane_ids < vint(texel_count); + vint texel_idxs(texel_indexes + i); + + vfloat data_r = gatherf(blk.data_r, texel_idxs); + vfloat data_g = gatherf(blk.data_g, texel_idxs); + vfloat data_b = gatherf(blk.data_b, texel_idxs); + vfloat data_a = gatherf(blk.data_a, texel_idxs); + + vfloat uncor_param = (data_r * l_uncor_bs0) + + (data_g * l_uncor_bs1) + + (data_b * l_uncor_bs2) + + (data_a * l_uncor_bs3); + + uncor_loparamv = min(uncor_param, uncor_loparamv); + uncor_hiparamv = max(uncor_param, uncor_hiparamv); + + vfloat uncor_dist0 = (l_uncor_amod0 - data_r) + + (uncor_param * l_uncor_bs0); + vfloat uncor_dist1 = (l_uncor_amod1 - data_g) + + (uncor_param * l_uncor_bs1); + vfloat uncor_dist2 = (l_uncor_amod2 - data_b) + + (uncor_param * l_uncor_bs2); + vfloat uncor_dist3 = (l_uncor_amod3 - data_a) + + (uncor_param * l_uncor_bs3); + + vfloat uncor_err = (ew_r * uncor_dist0 * uncor_dist0) + + (ew_g * uncor_dist1 * uncor_dist1) + + (ew_b * uncor_dist2 * uncor_dist2) + + (ew_a * uncor_dist3 * uncor_dist3); + + haccumulate(uncor_errorsumv, uncor_err, mask); + + // Process samechroma data + vfloat samec_param = (data_r * l_samec_bs0) + + (data_g * l_samec_bs1) + + (data_b * l_samec_bs2) + + (data_a * l_samec_bs3); + + samec_loparamv = min(samec_param, samec_loparamv); + samec_hiparamv = max(samec_param, samec_hiparamv); + + vfloat samec_dist0 = samec_param * l_samec_bs0 - data_r; + vfloat samec_dist1 = samec_param * l_samec_bs1 - data_g; + vfloat samec_dist2 = samec_param * l_samec_bs2 - data_b; + vfloat samec_dist3 = samec_param * l_samec_bs3 - data_a; + + vfloat samec_err = (ew_r * samec_dist0 * samec_dist0) + + (ew_g * samec_dist1 * samec_dist1) + + (ew_b * samec_dist2 * samec_dist2) + + (ew_a * samec_dist3 * samec_dist3); + + haccumulate(samec_errorsumv, samec_err, mask); + + lane_ids += vint(ASTCENC_SIMD_WIDTH); + } + + uncor_loparam = hmin_s(uncor_loparamv); + uncor_hiparam = hmax_s(uncor_hiparamv); + + samec_loparam = hmin_s(samec_loparamv); + samec_hiparam = hmax_s(samec_hiparamv); + + float uncor_linelen = uncor_hiparam - uncor_loparam; + float samec_linelen = samec_hiparam - samec_loparam; + + // Turn very small numbers and NaNs into a small number + uncor_lengths[partition] = astc::max(uncor_linelen, 1e-7f); + samec_lengths[partition] = astc::max(samec_linelen, 1e-7f); + } + + uncor_error = hadd_s(uncor_errorsumv); + samec_error = hadd_s(samec_errorsumv); +} + +/* See header for documentation. */ +void compute_error_squared_rgb( + const partition_info& pi, + const image_block& blk, + partition_lines3 plines[BLOCK_MAX_PARTITIONS], + float& uncor_error, + float& samec_error +) { + unsigned int partition_count = pi.partition_count; + promise(partition_count > 0); + + vfloatacc uncor_errorsumv = vfloatacc::zero(); + vfloatacc samec_errorsumv = vfloatacc::zero(); + + for (unsigned int partition = 0; partition < partition_count; partition++) + { + partition_lines3& pl = plines[partition]; + const uint8_t *texel_indexes = pi.texels_of_partition[partition]; + unsigned int texel_count = pi.partition_texel_count[partition]; + promise(texel_count > 0); + + float uncor_loparam = 1e10f; + float uncor_hiparam = -1e10f; + + float samec_loparam = 1e10f; + float samec_hiparam = -1e10f; + + processed_line3 l_uncor = pl.uncor_pline; + processed_line3 l_samec = pl.samec_pline; + + // This implementation is an example vectorization of this function. + // It works for - the codec is a 2-4% faster than not vectorizing - but + // the benefit is limited by the use of gathers and register pressure + + // Vectorize some useful scalar inputs + vfloat l_uncor_bs0(l_uncor.bs.lane<0>()); + vfloat l_uncor_bs1(l_uncor.bs.lane<1>()); + vfloat l_uncor_bs2(l_uncor.bs.lane<2>()); + + vfloat l_uncor_amod0(l_uncor.amod.lane<0>()); + vfloat l_uncor_amod1(l_uncor.amod.lane<1>()); + vfloat l_uncor_amod2(l_uncor.amod.lane<2>()); + + vfloat l_samec_bs0(l_samec.bs.lane<0>()); + vfloat l_samec_bs1(l_samec.bs.lane<1>()); + vfloat l_samec_bs2(l_samec.bs.lane<2>()); + + assert(all(l_samec.amod == vfloat4(0.0f))); + + vfloat uncor_loparamv(1e10f); + vfloat uncor_hiparamv(-1e10f); + + vfloat samec_loparamv(1e10f); + vfloat samec_hiparamv(-1e10f); + + vfloat ew_r(blk.channel_weight.lane<0>()); + vfloat ew_g(blk.channel_weight.lane<1>()); + vfloat ew_b(blk.channel_weight.lane<2>()); + + // This implementation over-shoots, but this is safe as we initialize the weights array + // to extend the last value. This means min/max are not impacted, but we need to mask + // out the dummy values when we compute the line weighting. + vint lane_ids = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vmask mask = lane_ids < vint(texel_count); + vint texel_idxs(texel_indexes + i); + + vfloat data_r = gatherf(blk.data_r, texel_idxs); + vfloat data_g = gatherf(blk.data_g, texel_idxs); + vfloat data_b = gatherf(blk.data_b, texel_idxs); + + vfloat uncor_param = (data_r * l_uncor_bs0) + + (data_g * l_uncor_bs1) + + (data_b * l_uncor_bs2); + + uncor_loparamv = min(uncor_param, uncor_loparamv); + uncor_hiparamv = max(uncor_param, uncor_hiparamv); + + vfloat uncor_dist0 = (l_uncor_amod0 - data_r) + + (uncor_param * l_uncor_bs0); + vfloat uncor_dist1 = (l_uncor_amod1 - data_g) + + (uncor_param * l_uncor_bs1); + vfloat uncor_dist2 = (l_uncor_amod2 - data_b) + + (uncor_param * l_uncor_bs2); + + vfloat uncor_err = (ew_r * uncor_dist0 * uncor_dist0) + + (ew_g * uncor_dist1 * uncor_dist1) + + (ew_b * uncor_dist2 * uncor_dist2); + + haccumulate(uncor_errorsumv, uncor_err, mask); + + // Process samechroma data + vfloat samec_param = (data_r * l_samec_bs0) + + (data_g * l_samec_bs1) + + (data_b * l_samec_bs2); + + samec_loparamv = min(samec_param, samec_loparamv); + samec_hiparamv = max(samec_param, samec_hiparamv); + + vfloat samec_dist0 = samec_param * l_samec_bs0 - data_r; + vfloat samec_dist1 = samec_param * l_samec_bs1 - data_g; + vfloat samec_dist2 = samec_param * l_samec_bs2 - data_b; + + vfloat samec_err = (ew_r * samec_dist0 * samec_dist0) + + (ew_g * samec_dist1 * samec_dist1) + + (ew_b * samec_dist2 * samec_dist2); + + haccumulate(samec_errorsumv, samec_err, mask); + + lane_ids += vint(ASTCENC_SIMD_WIDTH); + } + + uncor_loparam = hmin_s(uncor_loparamv); + uncor_hiparam = hmax_s(uncor_hiparamv); + + samec_loparam = hmin_s(samec_loparamv); + samec_hiparam = hmax_s(samec_hiparamv); + + float uncor_linelen = uncor_hiparam - uncor_loparam; + float samec_linelen = samec_hiparam - samec_loparam; + + // Turn very small numbers and NaNs into a small number + pl.uncor_line_len = astc::max(uncor_linelen, 1e-7f); + pl.samec_line_len = astc::max(samec_linelen, 1e-7f); + } + + uncor_error = hadd_s(uncor_errorsumv); + samec_error = hadd_s(samec_errorsumv); +} + +#endif diff --git a/thirdparty/astcenc/astcenc_block_sizes.cpp b/thirdparty/astcenc/astcenc_block_sizes.cpp new file mode 100644 index 0000000000..1c22d06a5c --- /dev/null +++ b/thirdparty/astcenc/astcenc_block_sizes.cpp @@ -0,0 +1,1184 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions to generate block size descriptor and decimation tables. + */ + +#include "astcenc_internal.h" + +/** + * @brief Decode the properties of an encoded 2D block mode. + * + * @param block_mode The encoded block mode. + * @param[out] x_weights The number of weights in the X dimension. + * @param[out] y_weights The number of weights in the Y dimension. + * @param[out] is_dual_plane True if this block mode has two weight planes. + * @param[out] quant_mode The quantization level for the weights. + * @param[out] weight_bits The storage bit count for the weights. + * + * @return Returns true if a valid mode, false otherwise. + */ +static bool decode_block_mode_2d( + unsigned int block_mode, + unsigned int& x_weights, + unsigned int& y_weights, + bool& is_dual_plane, + unsigned int& quant_mode, + unsigned int& weight_bits +) { + unsigned int base_quant_mode = (block_mode >> 4) & 1; + unsigned int H = (block_mode >> 9) & 1; + unsigned int D = (block_mode >> 10) & 1; + unsigned int A = (block_mode >> 5) & 0x3; + + x_weights = 0; + y_weights = 0; + + if ((block_mode & 3) != 0) + { + base_quant_mode |= (block_mode & 3) << 1; + unsigned int B = (block_mode >> 7) & 3; + switch ((block_mode >> 2) & 3) + { + case 0: + x_weights = B + 4; + y_weights = A + 2; + break; + case 1: + x_weights = B + 8; + y_weights = A + 2; + break; + case 2: + x_weights = A + 2; + y_weights = B + 8; + break; + case 3: + B &= 1; + if (block_mode & 0x100) + { + x_weights = B + 2; + y_weights = A + 2; + } + else + { + x_weights = A + 2; + y_weights = B + 6; + } + break; + } + } + else + { + base_quant_mode |= ((block_mode >> 2) & 3) << 1; + if (((block_mode >> 2) & 3) == 0) + { + return false; + } + + unsigned int B = (block_mode >> 9) & 3; + switch ((block_mode >> 7) & 3) + { + case 0: + x_weights = 12; + y_weights = A + 2; + break; + case 1: + x_weights = A + 2; + y_weights = 12; + break; + case 2: + x_weights = A + 6; + y_weights = B + 6; + D = 0; + H = 0; + break; + case 3: + switch ((block_mode >> 5) & 3) + { + case 0: + x_weights = 6; + y_weights = 10; + break; + case 1: + x_weights = 10; + y_weights = 6; + break; + case 2: + case 3: + return false; + } + break; + } + } + + unsigned int weight_count = x_weights * y_weights * (D + 1); + quant_mode = (base_quant_mode - 2) + 6 * H; + is_dual_plane = D != 0; + + weight_bits = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(quant_mode)); + return (weight_count <= BLOCK_MAX_WEIGHTS && + weight_bits >= BLOCK_MIN_WEIGHT_BITS && + weight_bits <= BLOCK_MAX_WEIGHT_BITS); +} + +/** + * @brief Decode the properties of an encoded 3D block mode. + * + * @param block_mode The encoded block mode. + * @param[out] x_weights The number of weights in the X dimension. + * @param[out] y_weights The number of weights in the Y dimension. + * @param[out] z_weights The number of weights in the Z dimension. + * @param[out] is_dual_plane True if this block mode has two weight planes. + * @param[out] quant_mode The quantization level for the weights. + * @param[out] weight_bits The storage bit count for the weights. + * + * @return Returns true if a valid mode, false otherwise. + */ +static bool decode_block_mode_3d( + unsigned int block_mode, + unsigned int& x_weights, + unsigned int& y_weights, + unsigned int& z_weights, + bool& is_dual_plane, + unsigned int& quant_mode, + unsigned int& weight_bits +) { + unsigned int base_quant_mode = (block_mode >> 4) & 1; + unsigned int H = (block_mode >> 9) & 1; + unsigned int D = (block_mode >> 10) & 1; + unsigned int A = (block_mode >> 5) & 0x3; + + x_weights = 0; + y_weights = 0; + z_weights = 0; + + if ((block_mode & 3) != 0) + { + base_quant_mode |= (block_mode & 3) << 1; + unsigned int B = (block_mode >> 7) & 3; + unsigned int C = (block_mode >> 2) & 0x3; + x_weights = A + 2; + y_weights = B + 2; + z_weights = C + 2; + } + else + { + base_quant_mode |= ((block_mode >> 2) & 3) << 1; + if (((block_mode >> 2) & 3) == 0) + { + return false; + } + + int B = (block_mode >> 9) & 3; + if (((block_mode >> 7) & 3) != 3) + { + D = 0; + H = 0; + } + switch ((block_mode >> 7) & 3) + { + case 0: + x_weights = 6; + y_weights = B + 2; + z_weights = A + 2; + break; + case 1: + x_weights = A + 2; + y_weights = 6; + z_weights = B + 2; + break; + case 2: + x_weights = A + 2; + y_weights = B + 2; + z_weights = 6; + break; + case 3: + x_weights = 2; + y_weights = 2; + z_weights = 2; + switch ((block_mode >> 5) & 3) + { + case 0: + x_weights = 6; + break; + case 1: + y_weights = 6; + break; + case 2: + z_weights = 6; + break; + case 3: + return false; + } + break; + } + } + + unsigned int weight_count = x_weights * y_weights * z_weights * (D + 1); + quant_mode = (base_quant_mode - 2) + 6 * H; + is_dual_plane = D != 0; + + weight_bits = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(quant_mode)); + return (weight_count <= BLOCK_MAX_WEIGHTS && + weight_bits >= BLOCK_MIN_WEIGHT_BITS && + weight_bits <= BLOCK_MAX_WEIGHT_BITS); +} + +/** + * @brief Create a 2D decimation entry for a block-size and weight-decimation pair. + * + * @param x_texels The number of texels in the X dimension. + * @param y_texels The number of texels in the Y dimension. + * @param x_weights The number of weights in the X dimension. + * @param y_weights The number of weights in the Y dimension. + * @param[out] di The decimation info structure to populate. + * @param[out] wb The decimation table init scratch working buffers. + */ +static void init_decimation_info_2d( + unsigned int x_texels, + unsigned int y_texels, + unsigned int x_weights, + unsigned int y_weights, + decimation_info& di, + dt_init_working_buffers& wb +) { + unsigned int texels_per_block = x_texels * y_texels; + unsigned int weights_per_block = x_weights * y_weights; + + uint8_t max_texel_count_of_weight = 0; + + promise(weights_per_block > 0); + promise(texels_per_block > 0); + promise(x_texels > 0); + promise(y_texels > 0); + + for (unsigned int i = 0; i < weights_per_block; i++) + { + wb.texel_count_of_weight[i] = 0; + } + + for (unsigned int i = 0; i < texels_per_block; i++) + { + wb.weight_count_of_texel[i] = 0; + } + + for (unsigned int y = 0; y < y_texels; y++) + { + for (unsigned int x = 0; x < x_texels; x++) + { + unsigned int texel = y * x_texels + x; + + unsigned int x_weight = (((1024 + x_texels / 2) / (x_texels - 1)) * x * (x_weights - 1) + 32) >> 6; + unsigned int y_weight = (((1024 + y_texels / 2) / (y_texels - 1)) * y * (y_weights - 1) + 32) >> 6; + + unsigned int x_weight_frac = x_weight & 0xF; + unsigned int y_weight_frac = y_weight & 0xF; + unsigned int x_weight_int = x_weight >> 4; + unsigned int y_weight_int = y_weight >> 4; + + unsigned int qweight[4]; + qweight[0] = x_weight_int + y_weight_int * x_weights; + qweight[1] = qweight[0] + 1; + qweight[2] = qweight[0] + x_weights; + qweight[3] = qweight[2] + 1; + + // Truncated-precision bilinear interpolation + unsigned int prod = x_weight_frac * y_weight_frac; + + unsigned int weight[4]; + weight[3] = (prod + 8) >> 4; + weight[1] = x_weight_frac - weight[3]; + weight[2] = y_weight_frac - weight[3]; + weight[0] = 16 - x_weight_frac - y_weight_frac + weight[3]; + + for (unsigned int i = 0; i < 4; i++) + { + if (weight[i] != 0) + { + wb.grid_weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(qweight[i]); + wb.weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(weight[i]); + wb.weight_count_of_texel[texel]++; + wb.texels_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(texel); + wb.texel_weights_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(weight[i]); + wb.texel_count_of_weight[qweight[i]]++; + max_texel_count_of_weight = astc::max(max_texel_count_of_weight, wb.texel_count_of_weight[qweight[i]]); + } + } + } + } + + uint8_t max_texel_weight_count = 0; + for (unsigned int i = 0; i < texels_per_block; i++) + { + di.texel_weight_count[i] = wb.weight_count_of_texel[i]; + max_texel_weight_count = astc::max(max_texel_weight_count, di.texel_weight_count[i]); + + for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++) + { + di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j]; + di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM); + di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j]; + } + + // Init all 4 entries so we can rely on zeros for vectorization + for (unsigned int j = wb.weight_count_of_texel[i]; j < 4; j++) + { + di.texel_weight_contribs_int_tr[j][i] = 0; + di.texel_weight_contribs_float_tr[j][i] = 0.0f; + di.texel_weights_tr[j][i] = 0; + } + } + + di.max_texel_weight_count = max_texel_weight_count; + + for (unsigned int i = 0; i < weights_per_block; i++) + { + unsigned int texel_count_wt = wb.texel_count_of_weight[i]; + di.weight_texel_count[i] = static_cast<uint8_t>(texel_count_wt); + + for (unsigned int j = 0; j < texel_count_wt; j++) + { + uint8_t texel = wb.texels_of_weight[i][j]; + + // Create transposed versions of these for better vectorization + di.weight_texels_tr[j][i] = texel; + di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]); + + // Store the per-texel contribution of this weight for each texel it contributes to + di.texel_contrib_for_weight[j][i] = 0.0f; + for (unsigned int k = 0; k < 4; k++) + { + uint8_t dttw = di.texel_weights_tr[k][texel]; + float dttwf = di.texel_weight_contribs_float_tr[k][texel]; + if (dttw == i && dttwf != 0.0f) + { + di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel]; + break; + } + } + } + + // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails + // Match last texel in active lane in SIMD group, for better gathers + uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i]; + for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++) + { + di.weight_texels_tr[j][i] = last_texel; + di.weights_texel_contribs_tr[j][i] = 0.0f; + } + } + + // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails + unsigned int texels_per_block_simd = round_up_to_simd_multiple_vla(texels_per_block); + for (unsigned int i = texels_per_block; i < texels_per_block_simd; i++) + { + di.texel_weight_count[i] = 0; + + for (unsigned int j = 0; j < 4; j++) + { + di.texel_weight_contribs_float_tr[j][i] = 0; + di.texel_weights_tr[j][i] = 0; + di.texel_weight_contribs_int_tr[j][i] = 0; + } + } + + // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails + // Match last texel in active lane in SIMD group, for better gathers + unsigned int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1]; + uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1]; + + unsigned int weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block); + for (unsigned int i = weights_per_block; i < weights_per_block_simd; i++) + { + di.weight_texel_count[i] = 0; + + for (unsigned int j = 0; j < max_texel_count_of_weight; j++) + { + di.weight_texels_tr[j][i] = last_texel; + di.weights_texel_contribs_tr[j][i] = 0.0f; + } + } + + di.texel_count = static_cast<uint8_t>(texels_per_block); + di.weight_count = static_cast<uint8_t>(weights_per_block); + di.weight_x = static_cast<uint8_t>(x_weights); + di.weight_y = static_cast<uint8_t>(y_weights); + di.weight_z = 1; +} + +/** + * @brief Create a 3D decimation entry for a block-size and weight-decimation pair. + * + * @param x_texels The number of texels in the X dimension. + * @param y_texels The number of texels in the Y dimension. + * @param z_texels The number of texels in the Z dimension. + * @param x_weights The number of weights in the X dimension. + * @param y_weights The number of weights in the Y dimension. + * @param z_weights The number of weights in the Z dimension. + * @param[out] di The decimation info structure to populate. + @param[out] wb The decimation table init scratch working buffers. + */ +static void init_decimation_info_3d( + unsigned int x_texels, + unsigned int y_texels, + unsigned int z_texels, + unsigned int x_weights, + unsigned int y_weights, + unsigned int z_weights, + decimation_info& di, + dt_init_working_buffers& wb +) { + unsigned int texels_per_block = x_texels * y_texels * z_texels; + unsigned int weights_per_block = x_weights * y_weights * z_weights; + + uint8_t max_texel_count_of_weight = 0; + + promise(weights_per_block > 0); + promise(texels_per_block > 0); + + for (unsigned int i = 0; i < weights_per_block; i++) + { + wb.texel_count_of_weight[i] = 0; + } + + for (unsigned int i = 0; i < texels_per_block; i++) + { + wb.weight_count_of_texel[i] = 0; + } + + for (unsigned int z = 0; z < z_texels; z++) + { + for (unsigned int y = 0; y < y_texels; y++) + { + for (unsigned int x = 0; x < x_texels; x++) + { + int texel = (z * y_texels + y) * x_texels + x; + + int x_weight = (((1024 + x_texels / 2) / (x_texels - 1)) * x * (x_weights - 1) + 32) >> 6; + int y_weight = (((1024 + y_texels / 2) / (y_texels - 1)) * y * (y_weights - 1) + 32) >> 6; + int z_weight = (((1024 + z_texels / 2) / (z_texels - 1)) * z * (z_weights - 1) + 32) >> 6; + + int x_weight_frac = x_weight & 0xF; + int y_weight_frac = y_weight & 0xF; + int z_weight_frac = z_weight & 0xF; + int x_weight_int = x_weight >> 4; + int y_weight_int = y_weight >> 4; + int z_weight_int = z_weight >> 4; + int qweight[4]; + int weight[4]; + qweight[0] = (z_weight_int * y_weights + y_weight_int) * x_weights + x_weight_int; + qweight[3] = ((z_weight_int + 1) * y_weights + (y_weight_int + 1)) * x_weights + (x_weight_int + 1); + + // simplex interpolation + int fs = x_weight_frac; + int ft = y_weight_frac; + int fp = z_weight_frac; + + int cas = ((fs > ft) << 2) + ((ft > fp) << 1) + ((fs > fp)); + int N = x_weights; + int NM = x_weights * y_weights; + + int s1, s2, w0, w1, w2, w3; + switch (cas) + { + case 7: + s1 = 1; + s2 = N; + w0 = 16 - fs; + w1 = fs - ft; + w2 = ft - fp; + w3 = fp; + break; + case 3: + s1 = N; + s2 = 1; + w0 = 16 - ft; + w1 = ft - fs; + w2 = fs - fp; + w3 = fp; + break; + case 5: + s1 = 1; + s2 = NM; + w0 = 16 - fs; + w1 = fs - fp; + w2 = fp - ft; + w3 = ft; + break; + case 4: + s1 = NM; + s2 = 1; + w0 = 16 - fp; + w1 = fp - fs; + w2 = fs - ft; + w3 = ft; + break; + case 2: + s1 = N; + s2 = NM; + w0 = 16 - ft; + w1 = ft - fp; + w2 = fp - fs; + w3 = fs; + break; + case 0: + s1 = NM; + s2 = N; + w0 = 16 - fp; + w1 = fp - ft; + w2 = ft - fs; + w3 = fs; + break; + default: + s1 = NM; + s2 = N; + w0 = 16 - fp; + w1 = fp - ft; + w2 = ft - fs; + w3 = fs; + break; + } + + qweight[1] = qweight[0] + s1; + qweight[2] = qweight[1] + s2; + weight[0] = w0; + weight[1] = w1; + weight[2] = w2; + weight[3] = w3; + + for (unsigned int i = 0; i < 4; i++) + { + if (weight[i] != 0) + { + wb.grid_weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(qweight[i]); + wb.weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(weight[i]); + wb.weight_count_of_texel[texel]++; + wb.texels_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(texel); + wb.texel_weights_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(weight[i]); + wb.texel_count_of_weight[qweight[i]]++; + max_texel_count_of_weight = astc::max(max_texel_count_of_weight, wb.texel_count_of_weight[qweight[i]]); + } + } + } + } + } + + uint8_t max_texel_weight_count = 0; + for (unsigned int i = 0; i < texels_per_block; i++) + { + di.texel_weight_count[i] = wb.weight_count_of_texel[i]; + max_texel_weight_count = astc::max(max_texel_weight_count, di.texel_weight_count[i]); + + // Init all 4 entries so we can rely on zeros for vectorization + for (unsigned int j = 0; j < 4; j++) + { + di.texel_weight_contribs_int_tr[j][i] = 0; + di.texel_weight_contribs_float_tr[j][i] = 0.0f; + di.texel_weights_tr[j][i] = 0; + } + + for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++) + { + di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j]; + di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM); + di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j]; + } + } + + di.max_texel_weight_count = max_texel_weight_count; + + for (unsigned int i = 0; i < weights_per_block; i++) + { + unsigned int texel_count_wt = wb.texel_count_of_weight[i]; + di.weight_texel_count[i] = static_cast<uint8_t>(texel_count_wt); + + for (unsigned int j = 0; j < texel_count_wt; j++) + { + unsigned int texel = wb.texels_of_weight[i][j]; + + // Create transposed versions of these for better vectorization + di.weight_texels_tr[j][i] = static_cast<uint8_t>(texel); + di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]); + + // Store the per-texel contribution of this weight for each texel it contributes to + di.texel_contrib_for_weight[j][i] = 0.0f; + for (unsigned int k = 0; k < 4; k++) + { + uint8_t dttw = di.texel_weights_tr[k][texel]; + float dttwf = di.texel_weight_contribs_float_tr[k][texel]; + if (dttw == i && dttwf != 0.0f) + { + di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel]; + break; + } + } + } + + // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails + // Match last texel in active lane in SIMD group, for better gathers + uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i]; + for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++) + { + di.weight_texels_tr[j][i] = last_texel; + di.weights_texel_contribs_tr[j][i] = 0.0f; + } + } + + // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails + unsigned int texels_per_block_simd = round_up_to_simd_multiple_vla(texels_per_block); + for (unsigned int i = texels_per_block; i < texels_per_block_simd; i++) + { + di.texel_weight_count[i] = 0; + + for (unsigned int j = 0; j < 4; j++) + { + di.texel_weight_contribs_float_tr[j][i] = 0; + di.texel_weights_tr[j][i] = 0; + di.texel_weight_contribs_int_tr[j][i] = 0; + } + } + + // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails + // Match last texel in active lane in SIMD group, for better gathers + int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1]; + uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1]; + + unsigned int weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block); + for (unsigned int i = weights_per_block; i < weights_per_block_simd; i++) + { + di.weight_texel_count[i] = 0; + + for (int j = 0; j < max_texel_count_of_weight; j++) + { + di.weight_texels_tr[j][i] = last_texel; + di.weights_texel_contribs_tr[j][i] = 0.0f; + } + } + + di.texel_count = static_cast<uint8_t>(texels_per_block); + di.weight_count = static_cast<uint8_t>(weights_per_block); + di.weight_x = static_cast<uint8_t>(x_weights); + di.weight_y = static_cast<uint8_t>(y_weights); + di.weight_z = static_cast<uint8_t>(z_weights); +} + +/** + * @brief Assign the texels to use for kmeans clustering. + * + * The max limit is @c BLOCK_MAX_KMEANS_TEXELS; above this a random selection is used. + * The @c bsd.texel_count is an input and must be populated beforehand. + * + * @param[in,out] bsd The block size descriptor to populate. + */ +static void assign_kmeans_texels( + block_size_descriptor& bsd +) { + // Use all texels for kmeans on a small block + if (bsd.texel_count <= BLOCK_MAX_KMEANS_TEXELS) + { + for (uint8_t i = 0; i < bsd.texel_count; i++) + { + bsd.kmeans_texels[i] = i; + } + + return; + } + + // Select a random subset of BLOCK_MAX_KMEANS_TEXELS for kmeans on a large block + uint64_t rng_state[2]; + astc::rand_init(rng_state); + + // Initialize array used for tracking used indices + bool seen[BLOCK_MAX_TEXELS]; + for (uint8_t i = 0; i < bsd.texel_count; i++) + { + seen[i] = false; + } + + // Assign 64 random indices, retrying if we see repeats + unsigned int arr_elements_set = 0; + while (arr_elements_set < BLOCK_MAX_KMEANS_TEXELS) + { + uint8_t texel = static_cast<uint8_t>(astc::rand(rng_state)); + texel = texel % bsd.texel_count; + if (!seen[texel]) + { + bsd.kmeans_texels[arr_elements_set++] = texel; + seen[texel] = true; + } + } +} + +/** + * @brief Allocate a single 2D decimation table entry. + * + * @param x_texels The number of texels in the X dimension. + * @param y_texels The number of texels in the Y dimension. + * @param x_weights The number of weights in the X dimension. + * @param y_weights The number of weights in the Y dimension. + * @param bsd The block size descriptor we are populating. + * @param wb The decimation table init scratch working buffers. + * @param index The packed array index to populate. + */ +static void construct_dt_entry_2d( + unsigned int x_texels, + unsigned int y_texels, + unsigned int x_weights, + unsigned int y_weights, + block_size_descriptor& bsd, + dt_init_working_buffers& wb, + unsigned int index +) { + unsigned int weight_count = x_weights * y_weights; + assert(weight_count <= BLOCK_MAX_WEIGHTS); + + bool try_2planes = (2 * weight_count) <= BLOCK_MAX_WEIGHTS; + + decimation_info& di = bsd.decimation_tables[index]; + init_decimation_info_2d(x_texels, y_texels, x_weights, y_weights, di, wb); + + int maxprec_1plane = -1; + int maxprec_2planes = -1; + for (int i = 0; i < 12; i++) + { + unsigned int bits_1plane = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(i)); + if (bits_1plane >= BLOCK_MIN_WEIGHT_BITS && bits_1plane <= BLOCK_MAX_WEIGHT_BITS) + { + maxprec_1plane = i; + } + + if (try_2planes) + { + unsigned int bits_2planes = get_ise_sequence_bitcount(2 * weight_count, static_cast<quant_method>(i)); + if (bits_2planes >= BLOCK_MIN_WEIGHT_BITS && bits_2planes <= BLOCK_MAX_WEIGHT_BITS) + { + maxprec_2planes = i; + } + } + } + + // At least one of the two should be valid ... + assert(maxprec_1plane >= 0 || maxprec_2planes >= 0); + bsd.decimation_modes[index].maxprec_1plane = static_cast<int8_t>(maxprec_1plane); + bsd.decimation_modes[index].maxprec_2planes = static_cast<int8_t>(maxprec_2planes); + bsd.decimation_modes[index].refprec_1_plane = 0; + bsd.decimation_modes[index].refprec_2_planes = 0; +} + +/** + * @brief Allocate block modes and decimation tables for a single 2D block size. + * + * @param x_texels The number of texels in the X dimension. + * @param y_texels The number of texels in the Y dimension. + * @param can_omit_modes Can we discard modes that astcenc won't use, even if legal? + * @param mode_cutoff Percentile cutoff in range [0,1]. Low values more likely to be used. + * @param[out] bsd The block size descriptor to populate. + */ +static void construct_block_size_descriptor_2d( + unsigned int x_texels, + unsigned int y_texels, + bool can_omit_modes, + float mode_cutoff, + block_size_descriptor& bsd +) { + // Store a remap table for storing packed decimation modes. + // Indexing uses [Y * 16 + X] and max size for each axis is 12. + static const unsigned int MAX_DMI = 12 * 16 + 12; + int decimation_mode_index[MAX_DMI]; + + dt_init_working_buffers* wb = new dt_init_working_buffers; + + bsd.xdim = static_cast<uint8_t>(x_texels); + bsd.ydim = static_cast<uint8_t>(y_texels); + bsd.zdim = 1; + bsd.texel_count = static_cast<uint8_t>(x_texels * y_texels); + + for (unsigned int i = 0; i < MAX_DMI; i++) + { + decimation_mode_index[i] = -1; + } + + // Gather all the decimation grids that can be used with the current block +#if !defined(ASTCENC_DECOMPRESS_ONLY) + const float *percentiles = get_2d_percentile_table(x_texels, y_texels); + float always_cutoff = 0.0f; +#else + // Unused in decompress-only builds + (void)can_omit_modes; + (void)mode_cutoff; +#endif + + // Construct the list of block formats referencing the decimation tables + unsigned int packed_bm_idx = 0; + unsigned int packed_dm_idx = 0; + + // Trackers + unsigned int bm_counts[4] { 0 }; + unsigned int dm_counts[4] { 0 }; + + // Clear the list to a known-bad value + for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) + { + bsd.block_mode_packed_index[i] = BLOCK_BAD_BLOCK_MODE; + } + + // Iterate four times to build a usefully ordered list: + // - Pass 0 - keep selected single plane "always" block modes + // - Pass 1 - keep selected single plane "non-always" block modes + // - Pass 2 - keep select dual plane block modes + // - Pass 3 - keep everything else that's legal + unsigned int limit = can_omit_modes ? 3 : 4; + for (unsigned int j = 0; j < limit; j ++) + { + for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) + { + // Skip modes we've already included in a previous pass + if (bsd.block_mode_packed_index[i] != BLOCK_BAD_BLOCK_MODE) + { + continue; + } + + // Decode parameters + unsigned int x_weights; + unsigned int y_weights; + bool is_dual_plane; + unsigned int quant_mode; + unsigned int weight_bits; + bool valid = decode_block_mode_2d(i, x_weights, y_weights, is_dual_plane, quant_mode, weight_bits); + + // Always skip invalid encodings for the current block size + if (!valid || (x_weights > x_texels) || (y_weights > y_texels)) + { + continue; + } + + // Selectively skip dual plane encodings + if (((j <= 1) && is_dual_plane) || (j == 2 && !is_dual_plane)) + { + continue; + } + + // Always skip encodings we can't physically encode based on + // generic encoding bit availability + if (is_dual_plane) + { + // This is the only check we need as only support 1 partition + if ((109 - weight_bits) <= 0) + { + continue; + } + } + else + { + // This is conservative - fewer bits may be available for > 1 partition + if ((111 - weight_bits) <= 0) + { + continue; + } + } + + // Selectively skip encodings based on percentile + bool percentile_hit = false; + #if !defined(ASTCENC_DECOMPRESS_ONLY) + if (j == 0) + { + percentile_hit = percentiles[i] <= always_cutoff; + } + else + { + percentile_hit = percentiles[i] <= mode_cutoff; + } + #endif + + if (j != 3 && !percentile_hit) + { + continue; + } + + // Allocate and initialize the decimation table entry if we've not used it yet + int decimation_mode = decimation_mode_index[y_weights * 16 + x_weights]; + if (decimation_mode < 0) + { + construct_dt_entry_2d(x_texels, y_texels, x_weights, y_weights, bsd, *wb, packed_dm_idx); + decimation_mode_index[y_weights * 16 + x_weights] = packed_dm_idx; + decimation_mode = packed_dm_idx; + + dm_counts[j]++; + packed_dm_idx++; + } + + auto& bm = bsd.block_modes[packed_bm_idx]; + + bm.decimation_mode = static_cast<uint8_t>(decimation_mode); + bm.quant_mode = static_cast<uint8_t>(quant_mode); + bm.is_dual_plane = static_cast<uint8_t>(is_dual_plane); + bm.weight_bits = static_cast<uint8_t>(weight_bits); + bm.mode_index = static_cast<uint16_t>(i); + + auto& dm = bsd.decimation_modes[decimation_mode]; + + if (is_dual_plane) + { + dm.set_ref_2_plane(bm.get_weight_quant_mode()); + } + else + { + dm.set_ref_1_plane(bm.get_weight_quant_mode()); + } + + bsd.block_mode_packed_index[i] = static_cast<uint16_t>(packed_bm_idx); + + packed_bm_idx++; + bm_counts[j]++; + } + } + + bsd.block_mode_count_1plane_always = bm_counts[0]; + bsd.block_mode_count_1plane_selected = bm_counts[0] + bm_counts[1]; + bsd.block_mode_count_1plane_2plane_selected = bm_counts[0] + bm_counts[1] + bm_counts[2]; + bsd.block_mode_count_all = bm_counts[0] + bm_counts[1] + bm_counts[2] + bm_counts[3]; + + bsd.decimation_mode_count_always = dm_counts[0]; + bsd.decimation_mode_count_selected = dm_counts[0] + dm_counts[1] + dm_counts[2]; + bsd.decimation_mode_count_all = dm_counts[0] + dm_counts[1] + dm_counts[2] + dm_counts[3]; + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + assert(bsd.block_mode_count_1plane_always > 0); + assert(bsd.decimation_mode_count_always > 0); + + delete[] percentiles; +#endif + + // Ensure the end of the array contains valid data (should never get read) + for (unsigned int i = bsd.decimation_mode_count_all; i < WEIGHTS_MAX_DECIMATION_MODES; i++) + { + bsd.decimation_modes[i].maxprec_1plane = -1; + bsd.decimation_modes[i].maxprec_2planes = -1; + bsd.decimation_modes[i].refprec_1_plane = 0; + bsd.decimation_modes[i].refprec_2_planes = 0; + } + + // Determine the texels to use for kmeans clustering. + assign_kmeans_texels(bsd); + + delete wb; +} + +/** + * @brief Allocate block modes and decimation tables for a single 3D block size. + * + * TODO: This function doesn't include all of the heuristics that we use for 2D block sizes such as + * the percentile mode cutoffs. If 3D becomes more widely used we should look at this. + * + * @param x_texels The number of texels in the X dimension. + * @param y_texels The number of texels in the Y dimension. + * @param z_texels The number of texels in the Z dimension. + * @param[out] bsd The block size descriptor to populate. + */ +static void construct_block_size_descriptor_3d( + unsigned int x_texels, + unsigned int y_texels, + unsigned int z_texels, + block_size_descriptor& bsd +) { + // Store a remap table for storing packed decimation modes. + // Indexing uses [Z * 64 + Y * 8 + X] and max size for each axis is 6. + static constexpr unsigned int MAX_DMI = 6 * 64 + 6 * 8 + 6; + int decimation_mode_index[MAX_DMI]; + unsigned int decimation_mode_count = 0; + + dt_init_working_buffers* wb = new dt_init_working_buffers; + + bsd.xdim = static_cast<uint8_t>(x_texels); + bsd.ydim = static_cast<uint8_t>(y_texels); + bsd.zdim = static_cast<uint8_t>(z_texels); + bsd.texel_count = static_cast<uint8_t>(x_texels * y_texels * z_texels); + + for (unsigned int i = 0; i < MAX_DMI; i++) + { + decimation_mode_index[i] = -1; + } + + // gather all the infill-modes that can be used with the current block size + for (unsigned int x_weights = 2; x_weights <= x_texels; x_weights++) + { + for (unsigned int y_weights = 2; y_weights <= y_texels; y_weights++) + { + for (unsigned int z_weights = 2; z_weights <= z_texels; z_weights++) + { + unsigned int weight_count = x_weights * y_weights * z_weights; + if (weight_count > BLOCK_MAX_WEIGHTS) + { + continue; + } + + decimation_info& di = bsd.decimation_tables[decimation_mode_count]; + decimation_mode_index[z_weights * 64 + y_weights * 8 + x_weights] = decimation_mode_count; + init_decimation_info_3d(x_texels, y_texels, z_texels, x_weights, y_weights, z_weights, di, *wb); + + int maxprec_1plane = -1; + int maxprec_2planes = -1; + for (unsigned int i = 0; i < 12; i++) + { + unsigned int bits_1plane = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(i)); + if (bits_1plane >= BLOCK_MIN_WEIGHT_BITS && bits_1plane <= BLOCK_MAX_WEIGHT_BITS) + { + maxprec_1plane = i; + } + + unsigned int bits_2planes = get_ise_sequence_bitcount(2 * weight_count, static_cast<quant_method>(i)); + if (bits_2planes >= BLOCK_MIN_WEIGHT_BITS && bits_2planes <= BLOCK_MAX_WEIGHT_BITS) + { + maxprec_2planes = i; + } + } + + if ((2 * weight_count) > BLOCK_MAX_WEIGHTS) + { + maxprec_2planes = -1; + } + + bsd.decimation_modes[decimation_mode_count].maxprec_1plane = static_cast<int8_t>(maxprec_1plane); + bsd.decimation_modes[decimation_mode_count].maxprec_2planes = static_cast<int8_t>(maxprec_2planes); + bsd.decimation_modes[decimation_mode_count].refprec_1_plane = maxprec_1plane == -1 ? 0 : 0xFFFF; + bsd.decimation_modes[decimation_mode_count].refprec_2_planes = maxprec_2planes == -1 ? 0 : 0xFFFF; + decimation_mode_count++; + } + } + } + + // Ensure the end of the array contains valid data (should never get read) + for (unsigned int i = decimation_mode_count; i < WEIGHTS_MAX_DECIMATION_MODES; i++) + { + bsd.decimation_modes[i].maxprec_1plane = -1; + bsd.decimation_modes[i].maxprec_2planes = -1; + bsd.decimation_modes[i].refprec_1_plane = 0; + bsd.decimation_modes[i].refprec_2_planes = 0; + } + + bsd.decimation_mode_count_always = 0; // Skipped for 3D modes + bsd.decimation_mode_count_selected = decimation_mode_count; + bsd.decimation_mode_count_all = decimation_mode_count; + + // Construct the list of block formats referencing the decimation tables + + // Clear the list to a known-bad value + for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) + { + bsd.block_mode_packed_index[i] = BLOCK_BAD_BLOCK_MODE; + } + + unsigned int packed_idx = 0; + unsigned int bm_counts[2] { 0 }; + + // Iterate two times to build a usefully ordered list: + // - Pass 0 - keep valid single plane block modes + // - Pass 1 - keep valid dual plane block modes + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) + { + // Skip modes we've already included in a previous pass + if (bsd.block_mode_packed_index[i] != BLOCK_BAD_BLOCK_MODE) + { + continue; + } + + unsigned int x_weights; + unsigned int y_weights; + unsigned int z_weights; + bool is_dual_plane; + unsigned int quant_mode; + unsigned int weight_bits; + + bool valid = decode_block_mode_3d(i, x_weights, y_weights, z_weights, is_dual_plane, quant_mode, weight_bits); + // Skip invalid encodings + if (!valid || x_weights > x_texels || y_weights > y_texels || z_weights > z_texels) + { + continue; + } + + // Skip encodings in the wrong iteration + if ((j == 0 && is_dual_plane) || (j == 1 && !is_dual_plane)) + { + continue; + } + + // Always skip encodings we can't physically encode based on bit availability + if (is_dual_plane) + { + // This is the only check we need as only support 1 partition + if ((109 - weight_bits) <= 0) + { + continue; + } + } + else + { + // This is conservative - fewer bits may be available for > 1 partition + if ((111 - weight_bits) <= 0) + { + continue; + } + } + + int decimation_mode = decimation_mode_index[z_weights * 64 + y_weights * 8 + x_weights]; + bsd.block_modes[packed_idx].decimation_mode = static_cast<uint8_t>(decimation_mode); + bsd.block_modes[packed_idx].quant_mode = static_cast<uint8_t>(quant_mode); + bsd.block_modes[packed_idx].weight_bits = static_cast<uint8_t>(weight_bits); + bsd.block_modes[packed_idx].is_dual_plane = static_cast<uint8_t>(is_dual_plane); + bsd.block_modes[packed_idx].mode_index = static_cast<uint16_t>(i); + + bsd.block_mode_packed_index[i] = static_cast<uint16_t>(packed_idx); + bm_counts[j]++; + packed_idx++; + } + } + + bsd.block_mode_count_1plane_always = 0; // Skipped for 3D modes + bsd.block_mode_count_1plane_selected = bm_counts[0]; + bsd.block_mode_count_1plane_2plane_selected = bm_counts[0] + bm_counts[1]; + bsd.block_mode_count_all = bm_counts[0] + bm_counts[1]; + + // Determine the texels to use for kmeans clustering. + assign_kmeans_texels(bsd); + + delete wb; +} + +/* See header for documentation. */ +void init_block_size_descriptor( + unsigned int x_texels, + unsigned int y_texels, + unsigned int z_texels, + bool can_omit_modes, + unsigned int partition_count_cutoff, + float mode_cutoff, + block_size_descriptor& bsd +) { + if (z_texels > 1) + { + construct_block_size_descriptor_3d(x_texels, y_texels, z_texels, bsd); + } + else + { + construct_block_size_descriptor_2d(x_texels, y_texels, can_omit_modes, mode_cutoff, bsd); + } + + init_partition_tables(bsd, can_omit_modes, partition_count_cutoff); +} diff --git a/thirdparty/astcenc/astcenc_color_quantize.cpp b/thirdparty/astcenc/astcenc_color_quantize.cpp new file mode 100644 index 0000000000..edcfe4f853 --- /dev/null +++ b/thirdparty/astcenc/astcenc_color_quantize.cpp @@ -0,0 +1,2071 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions for color quantization. + * + * The design of the color quantization functionality requires the caller to use higher level error + * analysis to determine the base encoding that should be used. This earlier analysis will select + * the basic type of the endpoint that should be used: + * + * * Mode: LDR or HDR + * * Quantization level + * * Channel count: L, LA, RGB, or RGBA + * * Endpoint 2 type: Direct color endcode, or scaled from endpoint 1. + * + * However, this leaves a number of decisions about exactly how to pack the endpoints open. In + * particular we need to determine if blue contraction can be used, or/and if delta encoding can be + * used. If they can be applied these will allow us to maintain higher precision in the endpoints + * without needing additional storage. + */ + +#include <stdio.h> +#include <assert.h> + +#include "astcenc_internal.h" + +/** + * @brief Determine the quantized value given a quantization level. + * + * @param quant_level The quantization level to use. + * @param value The value to convert. This may be outside of the 0-255 range and will be + * clamped before the value is looked up. + * + * @return The encoded quantized value. These are not necessarily in order; the compressor + * scrambles the values slightly to make hardware implementation easier. + */ +static inline uint8_t quant_color( + quant_method quant_level, + int value +) { + return color_unquant_to_uquant_tables[quant_level - QUANT_6][value]; +} + +/** + * @brief Quantize an LDR RGB color. + * + * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result. + * For this encoding @c color0 cannot be larger than @c color1. If @c color0 is actually larger + * than @c color1, @c color0 is reduced and @c color1 is increased until the constraint is met. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r0, r1, g0, g1, b0, b1). + * @param quant_level The quantization level to use. + */ +static void quantize_rgb( + vfloat4 color0, + vfloat4 color1, + uint8_t output[6], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float r0 = astc::clamp255f(color0.lane<0>() * scale); + float g0 = astc::clamp255f(color0.lane<1>() * scale); + float b0 = astc::clamp255f(color0.lane<2>() * scale); + + float r1 = astc::clamp255f(color1.lane<0>() * scale); + float g1 = astc::clamp255f(color1.lane<1>() * scale); + float b1 = astc::clamp255f(color1.lane<2>() * scale); + + int ri0, gi0, bi0, ri1, gi1, bi1; + float rgb0_addon = 0.5f; + float rgb1_addon = 0.5f; + do + { + ri0 = quant_color(quant_level, astc::max(astc::flt2int_rd(r0 + rgb0_addon), 0)); + gi0 = quant_color(quant_level, astc::max(astc::flt2int_rd(g0 + rgb0_addon), 0)); + bi0 = quant_color(quant_level, astc::max(astc::flt2int_rd(b0 + rgb0_addon), 0)); + ri1 = quant_color(quant_level, astc::min(astc::flt2int_rd(r1 + rgb1_addon), 255)); + gi1 = quant_color(quant_level, astc::min(astc::flt2int_rd(g1 + rgb1_addon), 255)); + bi1 = quant_color(quant_level, astc::min(astc::flt2int_rd(b1 + rgb1_addon), 255)); + + rgb0_addon -= 0.2f; + rgb1_addon += 0.2f; + } while (ri0 + gi0 + bi0 > ri1 + gi1 + bi1); + + output[0] = static_cast<uint8_t>(ri0); + output[1] = static_cast<uint8_t>(ri1); + output[2] = static_cast<uint8_t>(gi0); + output[3] = static_cast<uint8_t>(gi1); + output[4] = static_cast<uint8_t>(bi0); + output[5] = static_cast<uint8_t>(bi1); +} + +/** + * @brief Quantize an LDR RGBA color. + * + * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result. + * For this encoding @c color0.rgb cannot be larger than @c color1.rgb (this indicates blue + * contraction). If @c color0.rgb is actually larger than @c color1.rgb, @c color0.rgb is reduced + * and @c color1.rgb is increased until the constraint is met. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r0, r1, g0, g1, b0, b1, a0, a1). + * @param quant_level The quantization level to use. + */ +static void quantize_rgba( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float a0 = astc::clamp255f(color0.lane<3>() * scale); + float a1 = astc::clamp255f(color1.lane<3>() * scale); + + output[6] = quant_color(quant_level, astc::flt2int_rtn(a0)); + output[7] = quant_color(quant_level, astc::flt2int_rtn(a1)); + + quantize_rgb(color0, color1, output, quant_level); +} + +/** + * @brief Try to quantize an LDR RGB color using blue-contraction. + * + * Blue-contraction is only usable if encoded color 1 is larger than color 0. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r1, r0, g1, g0, b1, b0). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_rgb_blue_contract( + vfloat4 color0, + vfloat4 color1, + uint8_t output[6], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float r0 = color0.lane<0>() * scale; + float g0 = color0.lane<1>() * scale; + float b0 = color0.lane<2>() * scale; + + float r1 = color1.lane<0>() * scale; + float g1 = color1.lane<1>() * scale; + float b1 = color1.lane<2>() * scale; + + // Apply inverse blue-contraction. This can produce an overflow; which means BC cannot be used. + r0 += (r0 - b0); + g0 += (g0 - b0); + r1 += (r1 - b1); + g1 += (g1 - b1); + + if (r0 < 0.0f || r0 > 255.0f || g0 < 0.0f || g0 > 255.0f || b0 < 0.0f || b0 > 255.0f || + r1 < 0.0f || r1 > 255.0f || g1 < 0.0f || g1 > 255.0f || b1 < 0.0f || b1 > 255.0f) + { + return false; + } + + // Quantize the inverse-blue-contracted color + int ri0 = quant_color(quant_level, astc::flt2int_rtn(r0)); + int gi0 = quant_color(quant_level, astc::flt2int_rtn(g0)); + int bi0 = quant_color(quant_level, astc::flt2int_rtn(b0)); + + int ri1 = quant_color(quant_level, astc::flt2int_rtn(r1)); + int gi1 = quant_color(quant_level, astc::flt2int_rtn(g1)); + int bi1 = quant_color(quant_level, astc::flt2int_rtn(b1)); + + // If color #1 is not larger than color #0 then blue-contraction cannot be used. Note that + // blue-contraction and quantization change this order, which is why we must test afterwards. + if (ri1 + gi1 + bi1 <= ri0 + gi0 + bi0) + { + return false; + } + + output[0] = static_cast<uint8_t>(ri1); + output[1] = static_cast<uint8_t>(ri0); + output[2] = static_cast<uint8_t>(gi1); + output[3] = static_cast<uint8_t>(gi0); + output[4] = static_cast<uint8_t>(bi1); + output[5] = static_cast<uint8_t>(bi0); + + return true; +} + +/** + * @brief Try to quantize an LDR RGBA color using blue-contraction. + * + * Blue-contraction is only usable if encoded color 1 RGB is larger than color 0 RGB. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r1, r0, g1, g0, b1, b0, a1, a0). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static int try_quantize_rgba_blue_contract( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float a0 = astc::clamp255f(color0.lane<3>() * scale); + float a1 = astc::clamp255f(color1.lane<3>() * scale); + + output[6] = quant_color(quant_level, astc::flt2int_rtn(a1)); + output[7] = quant_color(quant_level, astc::flt2int_rtn(a0)); + + return try_quantize_rgb_blue_contract(color0, color1, output, quant_level); +} + +/** + * @brief Try to quantize an LDR RGB color using delta encoding. + * + * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; + * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is + * non-negative, then we encode a regular delta. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r0, r1, g0, g1, b0, b1). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_rgb_delta( + vfloat4 color0, + vfloat4 color1, + uint8_t output[6], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float r0 = astc::clamp255f(color0.lane<0>() * scale); + float g0 = astc::clamp255f(color0.lane<1>() * scale); + float b0 = astc::clamp255f(color0.lane<2>() * scale); + + float r1 = astc::clamp255f(color1.lane<0>() * scale); + float g1 = astc::clamp255f(color1.lane<1>() * scale); + float b1 = astc::clamp255f(color1.lane<2>() * scale); + + // Transform r0 to unorm9 + int r0a = astc::flt2int_rtn(r0); + int g0a = astc::flt2int_rtn(g0); + int b0a = astc::flt2int_rtn(b0); + + r0a <<= 1; + g0a <<= 1; + b0a <<= 1; + + // Mask off the top bit + int r0b = r0a & 0xFF; + int g0b = g0a & 0xFF; + int b0b = b0a & 0xFF; + + // Quantize then unquantize in order to get a value that we take differences against + int r0be = quant_color(quant_level, r0b); + int g0be = quant_color(quant_level, g0b); + int b0be = quant_color(quant_level, b0b); + + r0b = r0be | (r0a & 0x100); + g0b = g0be | (g0a & 0x100); + b0b = b0be | (b0a & 0x100); + + // Get hold of the second value + int r1d = astc::flt2int_rtn(r1); + int g1d = astc::flt2int_rtn(g1); + int b1d = astc::flt2int_rtn(b1); + + r1d <<= 1; + g1d <<= 1; + b1d <<= 1; + + // ... and take differences + r1d -= r0b; + g1d -= g0b; + b1d -= b0b; + + // Check if the difference is too large to be encodable + if (r1d > 63 || g1d > 63 || b1d > 63 || r1d < -64 || g1d < -64 || b1d < -64) + { + return false; + } + + // Insert top bit of the base into the offset + r1d &= 0x7F; + g1d &= 0x7F; + b1d &= 0x7F; + + r1d |= (r0b & 0x100) >> 1; + g1d |= (g0b & 0x100) >> 1; + b1d |= (b0b & 0x100) >> 1; + + // Then quantize and unquantize; if this causes either top two bits to flip, then encoding fails + // since we have then corrupted either the top bit of the base or the sign bit of the offset + int r1de = quant_color(quant_level, r1d); + int g1de = quant_color(quant_level, g1d); + int b1de = quant_color(quant_level, b1d); + + if (((r1d ^ r1de) | (g1d ^ g1de) | (b1d ^ b1de)) & 0xC0) + { + return false; + } + + // If the sum of offsets triggers blue-contraction then encoding fails + vint4 ep0(r0be, g0be, b0be, 0); + vint4 ep1(r1de, g1de, b1de, 0); + bit_transfer_signed(ep1, ep0); + if (hadd_rgb_s(ep1) < 0) + { + return false; + } + + // Check that the offsets produce legitimate sums as well + ep0 = ep0 + ep1; + if (any((ep0 < vint4(0)) | (ep0 > vint4(0xFF)))) + { + return false; + } + + output[0] = static_cast<uint8_t>(r0be); + output[1] = static_cast<uint8_t>(r1de); + output[2] = static_cast<uint8_t>(g0be); + output[3] = static_cast<uint8_t>(g1de); + output[4] = static_cast<uint8_t>(b0be); + output[5] = static_cast<uint8_t>(b1de); + + return true; +} + +static bool try_quantize_rgb_delta_blue_contract( + vfloat4 color0, + vfloat4 color1, + uint8_t output[6], + quant_method quant_level +) { + // Note: Switch around endpoint colors already at start + float scale = 1.0f / 257.0f; + + float r1 = color0.lane<0>() * scale; + float g1 = color0.lane<1>() * scale; + float b1 = color0.lane<2>() * scale; + + float r0 = color1.lane<0>() * scale; + float g0 = color1.lane<1>() * scale; + float b0 = color1.lane<2>() * scale; + + // Apply inverse blue-contraction. This can produce an overflow; which means BC cannot be used. + r0 += (r0 - b0); + g0 += (g0 - b0); + r1 += (r1 - b1); + g1 += (g1 - b1); + + if (r0 < 0.0f || r0 > 255.0f || g0 < 0.0f || g0 > 255.0f || b0 < 0.0f || b0 > 255.0f || + r1 < 0.0f || r1 > 255.0f || g1 < 0.0f || g1 > 255.0f || b1 < 0.0f || b1 > 255.0f) + { + return false; + } + + // Transform r0 to unorm9 + int r0a = astc::flt2int_rtn(r0); + int g0a = astc::flt2int_rtn(g0); + int b0a = astc::flt2int_rtn(b0); + r0a <<= 1; + g0a <<= 1; + b0a <<= 1; + + // Mask off the top bit + int r0b = r0a & 0xFF; + int g0b = g0a & 0xFF; + int b0b = b0a & 0xFF; + + // Quantize, then unquantize in order to get a value that we take differences against. + int r0be = quant_color(quant_level, r0b); + int g0be = quant_color(quant_level, g0b); + int b0be = quant_color(quant_level, b0b); + + r0b = r0be | (r0a & 0x100); + g0b = g0be | (g0a & 0x100); + b0b = b0be | (b0a & 0x100); + + // Get hold of the second value + int r1d = astc::flt2int_rtn(r1); + int g1d = astc::flt2int_rtn(g1); + int b1d = astc::flt2int_rtn(b1); + + r1d <<= 1; + g1d <<= 1; + b1d <<= 1; + + // .. and take differences! + r1d -= r0b; + g1d -= g0b; + b1d -= b0b; + + // Check if the difference is too large to be encodable + if (r1d > 63 || g1d > 63 || b1d > 63 || r1d < -64 || g1d < -64 || b1d < -64) + { + return false; + } + + // Insert top bit of the base into the offset + r1d &= 0x7F; + g1d &= 0x7F; + b1d &= 0x7F; + + r1d |= (r0b & 0x100) >> 1; + g1d |= (g0b & 0x100) >> 1; + b1d |= (b0b & 0x100) >> 1; + + // Then quantize and unquantize; if this causes any of the top two bits to flip, + // then encoding fails, since we have then corrupted either the top bit of the base + // or the sign bit of the offset. + int r1de = quant_color(quant_level, r1d); + int g1de = quant_color(quant_level, g1d); + int b1de = quant_color(quant_level, b1d); + + if (((r1d ^ r1de) | (g1d ^ g1de) | (b1d ^ b1de)) & 0xC0) + { + return false; + } + + // If the sum of offsets does not trigger blue-contraction then encoding fails + vint4 ep0(r0be, g0be, b0be, 0); + vint4 ep1(r1de, g1de, b1de, 0); + bit_transfer_signed(ep1, ep0); + if (hadd_rgb_s(ep1) >= 0) + { + return false; + } + + // Check that the offsets produce legitimate sums as well + ep0 = ep0 + ep1; + if (any((ep0 < vint4(0)) | (ep0 > vint4(0xFF)))) + { + return false; + } + + output[0] = static_cast<uint8_t>(r0be); + output[1] = static_cast<uint8_t>(r1de); + output[2] = static_cast<uint8_t>(g0be); + output[3] = static_cast<uint8_t>(g1de); + output[4] = static_cast<uint8_t>(b0be); + output[5] = static_cast<uint8_t>(b1de); + + return true; +} + +/** + * @brief Try to quantize an LDR A color using delta encoding. + * + * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; + * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is + * non-negative, then we encode a regular delta. + * + * This function only compressed the alpha - the other elements in the output array are not touched. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (x, x, x, x, x, x, a0, a1). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_alpha_delta( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float a0 = astc::clamp255f(color0.lane<3>() * scale); + float a1 = astc::clamp255f(color1.lane<3>() * scale); + + int a0a = astc::flt2int_rtn(a0); + a0a <<= 1; + int a0b = a0a & 0xFF; + int a0be = quant_color(quant_level, a0b); + a0b = a0be; + a0b |= a0a & 0x100; + int a1d = astc::flt2int_rtn(a1); + a1d <<= 1; + a1d -= a0b; + + if (a1d > 63 || a1d < -64) + { + return false; + } + + a1d &= 0x7F; + a1d |= (a0b & 0x100) >> 1; + + int a1de = quant_color(quant_level, a1d); + int a1du = a1de; + if ((a1d ^ a1du) & 0xC0) + { + return false; + } + + a1du &= 0x7F; + if (a1du & 0x40) + { + a1du -= 0x80; + } + + a1du += a0b; + if (a1du < 0 || a1du > 0x1FF) + { + return false; + } + + output[6] = static_cast<uint8_t>(a0be); + output[7] = static_cast<uint8_t>(a1de); + + return true; +} + +/** + * @brief Try to quantize an LDR LA color using delta encoding. + * + * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; + * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is + * non-negative, then we encode a regular delta. + * + * This function only compressed the alpha - the other elements in the output array are not touched. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (l0, l1, a0, a1). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_luminance_alpha_delta( + vfloat4 color0, + vfloat4 color1, + uint8_t output[4], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float l0 = astc::clamp255f(hadd_rgb_s(color0) * ((1.0f / 3.0f) * scale)); + float l1 = astc::clamp255f(hadd_rgb_s(color1) * ((1.0f / 3.0f) * scale)); + + float a0 = astc::clamp255f(color0.lane<3>() * scale); + float a1 = astc::clamp255f(color1.lane<3>() * scale); + + int l0a = astc::flt2int_rtn(l0); + int a0a = astc::flt2int_rtn(a0); + l0a <<= 1; + a0a <<= 1; + + int l0b = l0a & 0xFF; + int a0b = a0a & 0xFF; + int l0be = quant_color(quant_level, l0b); + int a0be = quant_color(quant_level, a0b); + l0b = l0be; + a0b = a0be; + l0b |= l0a & 0x100; + a0b |= a0a & 0x100; + + int l1d = astc::flt2int_rtn(l1); + int a1d = astc::flt2int_rtn(a1); + l1d <<= 1; + a1d <<= 1; + l1d -= l0b; + a1d -= a0b; + + if (l1d > 63 || l1d < -64) + { + return false; + } + + if (a1d > 63 || a1d < -64) + { + return false; + } + + l1d &= 0x7F; + a1d &= 0x7F; + l1d |= (l0b & 0x100) >> 1; + a1d |= (a0b & 0x100) >> 1; + + int l1de = quant_color(quant_level, l1d); + int a1de = quant_color(quant_level, a1d); + int l1du = l1de; + int a1du = a1de; + + if ((l1d ^ l1du) & 0xC0) + { + return false; + } + + if ((a1d ^ a1du) & 0xC0) + { + return false; + } + + l1du &= 0x7F; + a1du &= 0x7F; + + if (l1du & 0x40) + { + l1du -= 0x80; + } + + if (a1du & 0x40) + { + a1du -= 0x80; + } + + l1du += l0b; + a1du += a0b; + + if (l1du < 0 || l1du > 0x1FF) + { + return false; + } + + if (a1du < 0 || a1du > 0x1FF) + { + return false; + } + + output[0] = static_cast<uint8_t>(l0be); + output[1] = static_cast<uint8_t>(l1de); + output[2] = static_cast<uint8_t>(a0be); + output[3] = static_cast<uint8_t>(a1de); + + return true; +} + +/** + * @brief Try to quantize an LDR RGBA color using delta encoding. + * + * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; + * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is + * non-negative, then we encode a regular delta. + * + * This function only compressed the alpha - the other elements in the output array are not touched. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r0, r1, b0, b1, g0, g1, a0, a1). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_rgba_delta( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + return try_quantize_rgb_delta(color0, color1, output, quant_level) && + try_quantize_alpha_delta(color0, color1, output, quant_level); +} + + +/** + * @brief Try to quantize an LDR RGBA color using delta and blue contract encoding. + * + * At decode time we move one bit from the offset to the base and seize another bit as a sign bit; + * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is + * non-negative, then we encode a regular delta. + * + * This function only compressed the alpha - the other elements in the output array are not touched. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (r0, r1, b0, b1, g0, g1, a0, a1). + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_rgba_delta_blue_contract( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + // Note that we swap the color0 and color1 ordering for alpha to match RGB blue-contract + return try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level) && + try_quantize_alpha_delta(color1, color0, output, quant_level); +} + +/** + * @brief Quantize an LDR RGB color using scale encoding. + * + * @param color The input unquantized color endpoint and scale factor. + * @param[out] output The output endpoints, returned as (r0, g0, b0, s). + * @param quant_level The quantization level to use. + */ +static void quantize_rgbs( + vfloat4 color, + uint8_t output[4], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float r = astc::clamp255f(color.lane<0>() * scale); + float g = astc::clamp255f(color.lane<1>() * scale); + float b = astc::clamp255f(color.lane<2>() * scale); + + int ri = quant_color(quant_level, astc::flt2int_rtn(r)); + int gi = quant_color(quant_level, astc::flt2int_rtn(g)); + int bi = quant_color(quant_level, astc::flt2int_rtn(b)); + + float oldcolorsum = hadd_rgb_s(color) * scale; + float newcolorsum = static_cast<float>(ri + gi + bi); + + float scalea = astc::clamp1f(color.lane<3>() * (oldcolorsum + 1e-10f) / (newcolorsum + 1e-10f)); + int scale_idx = astc::flt2int_rtn(scalea * 256.0f); + scale_idx = astc::clamp(scale_idx, 0, 255); + + output[0] = static_cast<uint8_t>(ri); + output[1] = static_cast<uint8_t>(gi); + output[2] = static_cast<uint8_t>(bi); + output[3] = quant_color(quant_level, scale_idx); +} + +/** + * @brief Quantize an LDR RGBA color using scale encoding. + * + * @param color The input unquantized color endpoint and scale factor. + * @param[out] output The output endpoints, returned as (r0, g0, b0, s, a0, a1). + * @param quant_level The quantization level to use. + */ +static void quantize_rgbs_alpha( + vfloat4 color0, + vfloat4 color1, + vfloat4 color, + uint8_t output[6], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float a0 = astc::clamp255f(color0.lane<3>() * scale); + float a1 = astc::clamp255f(color1.lane<3>() * scale); + + output[4] = quant_color(quant_level, astc::flt2int_rtn(a0)); + output[5] = quant_color(quant_level, astc::flt2int_rtn(a1)); + + quantize_rgbs(color, output, quant_level); +} + +/** + * @brief Quantize a LDR L color. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (l0, l1). + * @param quant_level The quantization level to use. + */ +static void quantize_luminance( + vfloat4 color0, + vfloat4 color1, + uint8_t output[2], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + color0 = color0 * scale; + color1 = color1 * scale; + + float lum0 = astc::clamp255f(hadd_rgb_s(color0) * (1.0f / 3.0f)); + float lum1 = astc::clamp255f(hadd_rgb_s(color1) * (1.0f / 3.0f)); + + if (lum0 > lum1) + { + float avg = (lum0 + lum1) * 0.5f; + lum0 = avg; + lum1 = avg; + } + + output[0] = quant_color(quant_level, astc::flt2int_rtn(lum0)); + output[1] = quant_color(quant_level, astc::flt2int_rtn(lum1)); +} + +/** + * @brief Quantize a LDR LA color. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as (l0, l1, a0, a1). + * @param quant_level The quantization level to use. + */ +static void quantize_luminance_alpha( + vfloat4 color0, + vfloat4 color1, + uint8_t output[4], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + color0 = color0 * scale; + color1 = color1 * scale; + + float lum0 = astc::clamp255f(hadd_rgb_s(color0) * (1.0f / 3.0f)); + float lum1 = astc::clamp255f(hadd_rgb_s(color1) * (1.0f / 3.0f)); + + float a0 = astc::clamp255f(color0.lane<3>()); + float a1 = astc::clamp255f(color1.lane<3>()); + + // If endpoints are close then pull apart slightly; this gives > 8 bit normal map precision. + if (quant_level > 18) + { + if (fabsf(lum0 - lum1) < 3.0f) + { + if (lum0 < lum1) + { + lum0 -= 0.5f; + lum1 += 0.5f; + } + else + { + lum0 += 0.5f; + lum1 -= 0.5f; + } + + lum0 = astc::clamp255f(lum0); + lum1 = astc::clamp255f(lum1); + } + + if (fabsf(a0 - a1) < 3.0f) + { + if (a0 < a1) + { + a0 -= 0.5f; + a1 += 0.5f; + } + else + { + a0 += 0.5f; + a1 -= 0.5f; + } + + a0 = astc::clamp255f(a0); + a1 = astc::clamp255f(a1); + } + } + + output[0] = quant_color(quant_level, astc::flt2int_rtn(lum0)); + output[1] = quant_color(quant_level, astc::flt2int_rtn(lum1)); + output[2] = quant_color(quant_level, astc::flt2int_rtn(a0)); + output[3] = quant_color(quant_level, astc::flt2int_rtn(a1)); +} + +/** + * @brief Quantize and unquantize a value ensuring top two bits are the same. + * + * @param quant_level The quantization level to use. + * @param value The input unquantized value. + * @param[out] quant_value The quantized value. + */ +static inline void quantize_and_unquantize_retain_top_two_bits( + quant_method quant_level, + uint8_t value, + uint8_t& quant_value +) { + int perform_loop; + uint8_t quantval; + + do + { + quantval = quant_color(quant_level, value); + + // Perform looping if the top two bits were modified by quant/unquant + perform_loop = (value & 0xC0) != (quantval & 0xC0); + + if ((quantval & 0xC0) > (value & 0xC0)) + { + // Quant/unquant rounded UP so that the top two bits changed; + // decrement the input in hopes that this will avoid rounding up. + value--; + } + else if ((quantval & 0xC0) < (value & 0xC0)) + { + // Quant/unquant rounded DOWN so that the top two bits changed; + // decrement the input in hopes that this will avoid rounding down. + value--; + } + } while (perform_loop); + + quant_value = quantval; +} + +/** + * @brief Quantize and unquantize a value ensuring top four bits are the same. + * + * @param quant_level The quantization level to use. + * @param value The input unquantized value. + * @param[out] quant_value The quantized value in 0-255 range. + */ +static inline void quantize_and_unquantize_retain_top_four_bits( + quant_method quant_level, + uint8_t value, + uint8_t& quant_value +) { + uint8_t perform_loop; + uint8_t quantval; + + do + { + quantval = quant_color(quant_level, value); + // Perform looping if the top four bits were modified by quant/unquant + perform_loop = (value & 0xF0) != (quantval & 0xF0); + + if ((quantval & 0xF0) > (value & 0xF0)) + { + // Quant/unquant rounded UP so that the top four bits changed; + // decrement the input value in hopes that this will avoid rounding up. + value--; + } + else if ((quantval & 0xF0) < (value & 0xF0)) + { + // Quant/unquant rounded DOWN so that the top four bits changed; + // decrement the input value in hopes that this will avoid rounding down. + value--; + } + } while (perform_loop); + + quant_value = quantval; +} + +/** + * @brief Quantize a HDR RGB color using RGB + offset. + * + * @param color The input unquantized color endpoint and offset. + * @param[out] output The output endpoints, returned as packed RGBS with some mode bits. + * @param quant_level The quantization level to use. + */ +static void quantize_hdr_rgbo( + vfloat4 color, + uint8_t output[4], + quant_method quant_level +) { + color.set_lane<0>(color.lane<0>() + color.lane<3>()); + color.set_lane<1>(color.lane<1>() + color.lane<3>()); + color.set_lane<2>(color.lane<2>() + color.lane<3>()); + + color = clamp(0.0f, 65535.0f, color); + + vfloat4 color_bak = color; + + int majcomp; + if (color.lane<0>() > color.lane<1>() && color.lane<0>() > color.lane<2>()) + { + majcomp = 0; // red is largest component + } + else if (color.lane<1>() > color.lane<2>()) + { + majcomp = 1; // green is largest component + } + else + { + majcomp = 2; // blue is largest component + } + + // swap around the red component and the largest component. + switch (majcomp) + { + case 1: + color = color.swz<1, 0, 2, 3>(); + break; + case 2: + color = color.swz<2, 1, 0, 3>(); + break; + default: + break; + } + + static const int mode_bits[5][3] { + {11, 5, 7}, + {11, 6, 5}, + {10, 5, 8}, + {9, 6, 7}, + {8, 7, 6} + }; + + static const float mode_cutoffs[5][2] { + {1024, 4096}, + {2048, 1024}, + {2048, 16384}, + {8192, 16384}, + {32768, 16384} + }; + + static const float mode_rscales[5] { + 32.0f, + 32.0f, + 64.0f, + 128.0f, + 256.0f, + }; + + static const float mode_scales[5] { + 1.0f / 32.0f, + 1.0f / 32.0f, + 1.0f / 64.0f, + 1.0f / 128.0f, + 1.0f / 256.0f, + }; + + float r_base = color.lane<0>(); + float g_base = color.lane<0>() - color.lane<1>() ; + float b_base = color.lane<0>() - color.lane<2>() ; + float s_base = color.lane<3>() ; + + for (int mode = 0; mode < 5; mode++) + { + if (g_base > mode_cutoffs[mode][0] || b_base > mode_cutoffs[mode][0] || s_base > mode_cutoffs[mode][1]) + { + continue; + } + + // Encode the mode into a 4-bit vector + int mode_enc = mode < 4 ? (mode | (majcomp << 2)) : (majcomp | 0xC); + + float mode_scale = mode_scales[mode]; + float mode_rscale = mode_rscales[mode]; + + int gb_intcutoff = 1 << mode_bits[mode][1]; + int s_intcutoff = 1 << mode_bits[mode][2]; + + // Quantize and unquantize R + int r_intval = astc::flt2int_rtn(r_base * mode_scale); + + int r_lowbits = r_intval & 0x3f; + + r_lowbits |= (mode_enc & 3) << 6; + + uint8_t r_quantval; + quantize_and_unquantize_retain_top_two_bits( + quant_level, static_cast<uint8_t>(r_lowbits), r_quantval); + + r_intval = (r_intval & ~0x3f) | (r_quantval & 0x3f); + float r_fval = static_cast<float>(r_intval) * mode_rscale; + + // Recompute G and B, then quantize and unquantize them + float g_fval = r_fval - color.lane<1>() ; + float b_fval = r_fval - color.lane<2>() ; + + g_fval = astc::clamp(g_fval, 0.0f, 65535.0f); + b_fval = astc::clamp(b_fval, 0.0f, 65535.0f); + + int g_intval = astc::flt2int_rtn(g_fval * mode_scale); + int b_intval = astc::flt2int_rtn(b_fval * mode_scale); + + if (g_intval >= gb_intcutoff || b_intval >= gb_intcutoff) + { + continue; + } + + int g_lowbits = g_intval & 0x1f; + int b_lowbits = b_intval & 0x1f; + + int bit0 = 0; + int bit1 = 0; + int bit2 = 0; + int bit3 = 0; + + switch (mode) + { + case 0: + case 2: + bit0 = (r_intval >> 9) & 1; + break; + case 1: + case 3: + bit0 = (r_intval >> 8) & 1; + break; + case 4: + case 5: + bit0 = (g_intval >> 6) & 1; + break; + } + + switch (mode) + { + case 0: + case 1: + case 2: + case 3: + bit2 = (r_intval >> 7) & 1; + break; + case 4: + case 5: + bit2 = (b_intval >> 6) & 1; + break; + } + + switch (mode) + { + case 0: + case 2: + bit1 = (r_intval >> 8) & 1; + break; + case 1: + case 3: + case 4: + case 5: + bit1 = (g_intval >> 5) & 1; + break; + } + + switch (mode) + { + case 0: + bit3 = (r_intval >> 10) & 1; + break; + case 2: + bit3 = (r_intval >> 6) & 1; + break; + case 1: + case 3: + case 4: + case 5: + bit3 = (b_intval >> 5) & 1; + break; + } + + g_lowbits |= (mode_enc & 0x4) << 5; + b_lowbits |= (mode_enc & 0x8) << 4; + + g_lowbits |= bit0 << 6; + g_lowbits |= bit1 << 5; + b_lowbits |= bit2 << 6; + b_lowbits |= bit3 << 5; + + uint8_t g_quantval; + uint8_t b_quantval; + + quantize_and_unquantize_retain_top_four_bits( + quant_level, static_cast<uint8_t>(g_lowbits), g_quantval); + quantize_and_unquantize_retain_top_four_bits( + quant_level, static_cast<uint8_t>(b_lowbits), b_quantval); + + g_intval = (g_intval & ~0x1f) | (g_quantval & 0x1f); + b_intval = (b_intval & ~0x1f) | (b_quantval & 0x1f); + + g_fval = static_cast<float>(g_intval) * mode_rscale; + b_fval = static_cast<float>(b_intval) * mode_rscale; + + // Recompute the scale value, based on the errors introduced to red, green and blue + + // If the error is positive, then the R,G,B errors combined have raised the color + // value overall; as such, the scale value needs to be increased. + float rgb_errorsum = (r_fval - color.lane<0>() ) + (r_fval - g_fval - color.lane<1>() ) + (r_fval - b_fval - color.lane<2>() ); + + float s_fval = s_base + rgb_errorsum * (1.0f / 3.0f); + s_fval = astc::clamp(s_fval, 0.0f, 1e9f); + + int s_intval = astc::flt2int_rtn(s_fval * mode_scale); + + if (s_intval >= s_intcutoff) + { + continue; + } + + int s_lowbits = s_intval & 0x1f; + + int bit4; + int bit5; + int bit6; + switch (mode) + { + case 1: + bit6 = (r_intval >> 9) & 1; + break; + default: + bit6 = (s_intval >> 5) & 1; + break; + } + + switch (mode) + { + case 4: + bit5 = (r_intval >> 7) & 1; + break; + case 1: + bit5 = (r_intval >> 10) & 1; + break; + default: + bit5 = (s_intval >> 6) & 1; + break; + } + + switch (mode) + { + case 2: + bit4 = (s_intval >> 7) & 1; + break; + default: + bit4 = (r_intval >> 6) & 1; + break; + } + + s_lowbits |= bit6 << 5; + s_lowbits |= bit5 << 6; + s_lowbits |= bit4 << 7; + + uint8_t s_quantval; + + quantize_and_unquantize_retain_top_four_bits( + quant_level, static_cast<uint8_t>(s_lowbits), s_quantval); + + output[0] = r_quantval; + output[1] = g_quantval; + output[2] = b_quantval; + output[3] = s_quantval; + return; + } + + // Failed to encode any of the modes above? In that case encode using mode #5 + float vals[4]; + vals[0] = color_bak.lane<0>(); + vals[1] = color_bak.lane<1>(); + vals[2] = color_bak.lane<2>(); + vals[3] = color_bak.lane<3>(); + + int ivals[4]; + float cvals[3]; + + for (int i = 0; i < 3; i++) + { + vals[i] = astc::clamp(vals[i], 0.0f, 65020.0f); + ivals[i] = astc::flt2int_rtn(vals[i] * (1.0f / 512.0f)); + cvals[i] = static_cast<float>(ivals[i]) * 512.0f; + } + + float rgb_errorsum = (cvals[0] - vals[0]) + (cvals[1] - vals[1]) + (cvals[2] - vals[2]); + vals[3] += rgb_errorsum * (1.0f / 3.0f); + + vals[3] = astc::clamp(vals[3], 0.0f, 65020.0f); + ivals[3] = astc::flt2int_rtn(vals[3] * (1.0f / 512.0f)); + + int encvals[4]; + encvals[0] = (ivals[0] & 0x3f) | 0xC0; + encvals[1] = (ivals[1] & 0x7f) | 0x80; + encvals[2] = (ivals[2] & 0x7f) | 0x80; + encvals[3] = (ivals[3] & 0x7f) | ((ivals[0] & 0x40) << 1); + + for (uint8_t i = 0; i < 4; i++) + { + quantize_and_unquantize_retain_top_four_bits( + quant_level, static_cast<uint8_t>(encvals[i]), output[i]); + } + + return; +} + +/** + * @brief Quantize a HDR RGB color using direct RGB encoding. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as packed RGB+RGB pairs with mode bits. + * @param quant_level The quantization level to use. + */ +static void quantize_hdr_rgb( + vfloat4 color0, + vfloat4 color1, + uint8_t output[6], + quant_method quant_level +) { + // Note: color*.lane<3> is not used so we can ignore it + color0 = clamp(0.0f, 65535.0f, color0); + color1 = clamp(0.0f, 65535.0f, color1); + + vfloat4 color0_bak = color0; + vfloat4 color1_bak = color1; + + int majcomp; + if (color1.lane<0>() > color1.lane<1>() && color1.lane<0>() > color1.lane<2>()) + { + majcomp = 0; + } + else if (color1.lane<1>() > color1.lane<2>()) + { + majcomp = 1; + } + else + { + majcomp = 2; + } + + // Swizzle the components + switch (majcomp) + { + case 1: // red-green swap + color0 = color0.swz<1, 0, 2, 3>(); + color1 = color1.swz<1, 0, 2, 3>(); + break; + case 2: // red-blue swap + color0 = color0.swz<2, 1, 0, 3>(); + color1 = color1.swz<2, 1, 0, 3>(); + break; + default: + break; + } + + float a_base = color1.lane<0>(); + a_base = astc::clamp(a_base, 0.0f, 65535.0f); + + float b0_base = a_base - color1.lane<1>(); + float b1_base = a_base - color1.lane<2>(); + float c_base = a_base - color0.lane<0>(); + float d0_base = a_base - b0_base - c_base - color0.lane<1>(); + float d1_base = a_base - b1_base - c_base - color0.lane<2>(); + + // Number of bits in the various fields in the various modes + static const int mode_bits[8][4] { + {9, 7, 6, 7}, + {9, 8, 6, 6}, + {10, 6, 7, 7}, + {10, 7, 7, 6}, + {11, 8, 6, 5}, + {11, 6, 8, 6}, + {12, 7, 7, 5}, + {12, 6, 7, 6} + }; + + // Cutoffs to use for the computed values of a,b,c,d, assuming the + // range 0..65535 are LNS values corresponding to fp16. + static const float mode_cutoffs[8][4] { + {16384, 8192, 8192, 8}, // mode 0: 9,7,6,7 + {32768, 8192, 4096, 8}, // mode 1: 9,8,6,6 + {4096, 8192, 4096, 4}, // mode 2: 10,6,7,7 + {8192, 8192, 2048, 4}, // mode 3: 10,7,7,6 + {8192, 2048, 512, 2}, // mode 4: 11,8,6,5 + {2048, 8192, 1024, 2}, // mode 5: 11,6,8,6 + {2048, 2048, 256, 1}, // mode 6: 12,7,7,5 + {1024, 2048, 512, 1}, // mode 7: 12,6,7,6 + }; + + static const float mode_scales[8] { + 1.0f / 128.0f, + 1.0f / 128.0f, + 1.0f / 64.0f, + 1.0f / 64.0f, + 1.0f / 32.0f, + 1.0f / 32.0f, + 1.0f / 16.0f, + 1.0f / 16.0f, + }; + + // Scaling factors when going from what was encoded in the mode to 16 bits. + static const float mode_rscales[8] { + 128.0f, + 128.0f, + 64.0f, + 64.0f, + 32.0f, + 32.0f, + 16.0f, + 16.0f + }; + + // Try modes one by one, with the highest-precision mode first. + for (int mode = 7; mode >= 0; mode--) + { + // For each mode, test if we can in fact accommodate the computed b, c, and d values. + // If we clearly can't, then we skip to the next mode. + + float b_cutoff = mode_cutoffs[mode][0]; + float c_cutoff = mode_cutoffs[mode][1]; + float d_cutoff = mode_cutoffs[mode][2]; + + if (b0_base > b_cutoff || b1_base > b_cutoff || c_base > c_cutoff || fabsf(d0_base) > d_cutoff || fabsf(d1_base) > d_cutoff) + { + continue; + } + + float mode_scale = mode_scales[mode]; + float mode_rscale = mode_rscales[mode]; + + int b_intcutoff = 1 << mode_bits[mode][1]; + int c_intcutoff = 1 << mode_bits[mode][2]; + int d_intcutoff = 1 << (mode_bits[mode][3] - 1); + + // Quantize and unquantize A, with the assumption that its high bits can be handled safely. + int a_intval = astc::flt2int_rtn(a_base * mode_scale); + int a_lowbits = a_intval & 0xFF; + + int a_quantval = quant_color(quant_level, a_lowbits); + int a_uquantval = a_quantval; + a_intval = (a_intval & ~0xFF) | a_uquantval; + float a_fval = static_cast<float>(a_intval) * mode_rscale; + + // Recompute C, then quantize and unquantize it + float c_fval = a_fval - color0.lane<0>(); + c_fval = astc::clamp(c_fval, 0.0f, 65535.0f); + + int c_intval = astc::flt2int_rtn(c_fval * mode_scale); + + if (c_intval >= c_intcutoff) + { + continue; + } + + int c_lowbits = c_intval & 0x3f; + + c_lowbits |= (mode & 1) << 7; + c_lowbits |= (a_intval & 0x100) >> 2; + + uint8_t c_quantval; + + quantize_and_unquantize_retain_top_two_bits( + quant_level, static_cast<uint8_t>(c_lowbits), c_quantval); + + c_intval = (c_intval & ~0x3F) | (c_quantval & 0x3F); + c_fval = static_cast<float>(c_intval) * mode_rscale; + + // Recompute B0 and B1, then quantize and unquantize them + float b0_fval = a_fval - color1.lane<1>(); + float b1_fval = a_fval - color1.lane<2>(); + + b0_fval = astc::clamp(b0_fval, 0.0f, 65535.0f); + b1_fval = astc::clamp(b1_fval, 0.0f, 65535.0f); + int b0_intval = astc::flt2int_rtn(b0_fval * mode_scale); + int b1_intval = astc::flt2int_rtn(b1_fval * mode_scale); + + if (b0_intval >= b_intcutoff || b1_intval >= b_intcutoff) + { + continue; + } + + int b0_lowbits = b0_intval & 0x3f; + int b1_lowbits = b1_intval & 0x3f; + + int bit0 = 0; + int bit1 = 0; + switch (mode) + { + case 0: + case 1: + case 3: + case 4: + case 6: + bit0 = (b0_intval >> 6) & 1; + break; + case 2: + case 5: + case 7: + bit0 = (a_intval >> 9) & 1; + break; + } + + switch (mode) + { + case 0: + case 1: + case 3: + case 4: + case 6: + bit1 = (b1_intval >> 6) & 1; + break; + case 2: + bit1 = (c_intval >> 6) & 1; + break; + case 5: + case 7: + bit1 = (a_intval >> 10) & 1; + break; + } + + b0_lowbits |= bit0 << 6; + b1_lowbits |= bit1 << 6; + + b0_lowbits |= ((mode >> 1) & 1) << 7; + b1_lowbits |= ((mode >> 2) & 1) << 7; + + uint8_t b0_quantval; + uint8_t b1_quantval; + + quantize_and_unquantize_retain_top_two_bits( + quant_level, static_cast<uint8_t>(b0_lowbits), b0_quantval); + quantize_and_unquantize_retain_top_two_bits( + quant_level, static_cast<uint8_t>(b1_lowbits), b1_quantval); + + b0_intval = (b0_intval & ~0x3f) | (b0_quantval & 0x3f); + b1_intval = (b1_intval & ~0x3f) | (b1_quantval & 0x3f); + b0_fval = static_cast<float>(b0_intval) * mode_rscale; + b1_fval = static_cast<float>(b1_intval) * mode_rscale; + + // Recompute D0 and D1, then quantize and unquantize them + float d0_fval = a_fval - b0_fval - c_fval - color0.lane<1>(); + float d1_fval = a_fval - b1_fval - c_fval - color0.lane<2>(); + + d0_fval = astc::clamp(d0_fval, -65535.0f, 65535.0f); + d1_fval = astc::clamp(d1_fval, -65535.0f, 65535.0f); + + int d0_intval = astc::flt2int_rtn(d0_fval * mode_scale); + int d1_intval = astc::flt2int_rtn(d1_fval * mode_scale); + + if (abs(d0_intval) >= d_intcutoff || abs(d1_intval) >= d_intcutoff) + { + continue; + } + + int d0_lowbits = d0_intval & 0x1f; + int d1_lowbits = d1_intval & 0x1f; + + int bit2 = 0; + int bit3 = 0; + int bit4; + int bit5; + switch (mode) + { + case 0: + case 2: + bit2 = (d0_intval >> 6) & 1; + break; + case 1: + case 4: + bit2 = (b0_intval >> 7) & 1; + break; + case 3: + bit2 = (a_intval >> 9) & 1; + break; + case 5: + bit2 = (c_intval >> 7) & 1; + break; + case 6: + case 7: + bit2 = (a_intval >> 11) & 1; + break; + } + switch (mode) + { + case 0: + case 2: + bit3 = (d1_intval >> 6) & 1; + break; + case 1: + case 4: + bit3 = (b1_intval >> 7) & 1; + break; + case 3: + case 5: + case 6: + case 7: + bit3 = (c_intval >> 6) & 1; + break; + } + + switch (mode) + { + case 4: + case 6: + bit4 = (a_intval >> 9) & 1; + bit5 = (a_intval >> 10) & 1; + break; + default: + bit4 = (d0_intval >> 5) & 1; + bit5 = (d1_intval >> 5) & 1; + break; + } + + d0_lowbits |= bit2 << 6; + d1_lowbits |= bit3 << 6; + d0_lowbits |= bit4 << 5; + d1_lowbits |= bit5 << 5; + + d0_lowbits |= (majcomp & 1) << 7; + d1_lowbits |= ((majcomp >> 1) & 1) << 7; + + uint8_t d0_quantval; + uint8_t d1_quantval; + + quantize_and_unquantize_retain_top_four_bits( + quant_level, static_cast<uint8_t>(d0_lowbits), d0_quantval); + quantize_and_unquantize_retain_top_four_bits( + quant_level, static_cast<uint8_t>(d1_lowbits), d1_quantval); + + output[0] = static_cast<uint8_t>(a_quantval); + output[1] = c_quantval; + output[2] = b0_quantval; + output[3] = b1_quantval; + output[4] = d0_quantval; + output[5] = d1_quantval; + return; + } + + // If neither of the modes fit we will use a flat representation for storing data, using 8 bits + // for red and green, and 7 bits for blue. This gives color accuracy roughly similar to LDR + // 4:4:3 which is not at all great but usable. This representation is used if the light color is + // more than 4x the color value of the dark color. + float vals[6]; + vals[0] = color0_bak.lane<0>(); + vals[1] = color1_bak.lane<0>(); + vals[2] = color0_bak.lane<1>(); + vals[3] = color1_bak.lane<1>(); + vals[4] = color0_bak.lane<2>(); + vals[5] = color1_bak.lane<2>(); + + for (int i = 0; i < 6; i++) + { + vals[i] = astc::clamp(vals[i], 0.0f, 65020.0f); + } + + for (int i = 0; i < 4; i++) + { + int idx = astc::flt2int_rtn(vals[i] * 1.0f / 256.0f); + output[i] = quant_color(quant_level, idx); + } + + for (int i = 4; i < 6; i++) + { + int idx = astc::flt2int_rtn(vals[i] * 1.0f / 512.0f) + 128; + quantize_and_unquantize_retain_top_two_bits( + quant_level, static_cast<uint8_t>(idx), output[i]); + } + + return; +} + +/** + * @brief Quantize a HDR RGB + LDR A color using direct RGBA encoding. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits. + * @param quant_level The quantization level to use. + */ +static void quantize_hdr_rgb_ldr_alpha( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + float scale = 1.0f / 257.0f; + + float a0 = astc::clamp255f(color0.lane<3>() * scale); + float a1 = astc::clamp255f(color1.lane<3>() * scale); + + output[6] = quant_color(quant_level, astc::flt2int_rtn(a0)); + output[7] = quant_color(quant_level, astc::flt2int_rtn(a1)); + + quantize_hdr_rgb(color0, color1, output, quant_level); +} + +/** + * @brief Quantize a HDR L color using the large range encoding. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as packed (l0, l1). + * @param quant_level The quantization level to use. + */ +static void quantize_hdr_luminance_large_range( + vfloat4 color0, + vfloat4 color1, + uint8_t output[2], + quant_method quant_level +) { + float lum0 = hadd_rgb_s(color0) * (1.0f / 3.0f); + float lum1 = hadd_rgb_s(color1) * (1.0f / 3.0f); + + if (lum1 < lum0) + { + float avg = (lum0 + lum1) * 0.5f; + lum0 = avg; + lum1 = avg; + } + + int ilum1 = astc::flt2int_rtn(lum1); + int ilum0 = astc::flt2int_rtn(lum0); + + // Find the closest encodable point in the upper half of the code-point space + int upper_v0 = (ilum0 + 128) >> 8; + int upper_v1 = (ilum1 + 128) >> 8; + + upper_v0 = astc::clamp(upper_v0, 0, 255); + upper_v1 = astc::clamp(upper_v1, 0, 255); + + // Find the closest encodable point in the lower half of the code-point space + int lower_v0 = (ilum1 + 256) >> 8; + int lower_v1 = ilum0 >> 8; + + lower_v0 = astc::clamp(lower_v0, 0, 255); + lower_v1 = astc::clamp(lower_v1, 0, 255); + + // Determine the distance between the point in code-point space and the input value + int upper0_dec = upper_v0 << 8; + int upper1_dec = upper_v1 << 8; + int lower0_dec = (lower_v1 << 8) + 128; + int lower1_dec = (lower_v0 << 8) - 128; + + int upper0_diff = upper0_dec - ilum0; + int upper1_diff = upper1_dec - ilum1; + int lower0_diff = lower0_dec - ilum0; + int lower1_diff = lower1_dec - ilum1; + + int upper_error = (upper0_diff * upper0_diff) + (upper1_diff * upper1_diff); + int lower_error = (lower0_diff * lower0_diff) + (lower1_diff * lower1_diff); + + int v0, v1; + if (upper_error < lower_error) + { + v0 = upper_v0; + v1 = upper_v1; + } + else + { + v0 = lower_v0; + v1 = lower_v1; + } + + // OK; encode + output[0] = quant_color(quant_level, v0); + output[1] = quant_color(quant_level, v1); +} + +/** + * @brief Quantize a HDR L color using the small range encoding. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as packed (l0, l1) with mode bits. + * @param quant_level The quantization level to use. + * + * @return Returns @c false on failure, @c true on success. + */ +static bool try_quantize_hdr_luminance_small_range( + vfloat4 color0, + vfloat4 color1, + uint8_t output[2], + quant_method quant_level +) { + float lum0 = hadd_rgb_s(color0) * (1.0f / 3.0f); + float lum1 = hadd_rgb_s(color1) * (1.0f / 3.0f); + + if (lum1 < lum0) + { + float avg = (lum0 + lum1) * 0.5f; + lum0 = avg; + lum1 = avg; + } + + int ilum1 = astc::flt2int_rtn(lum1); + int ilum0 = astc::flt2int_rtn(lum0); + + // Difference of more than a factor-of-2 results in immediate failure + if (ilum1 - ilum0 > 2048) + { + return false; + } + + int lowval, highval, diffval; + int v0, v1; + int v0e, v1e; + int v0d, v1d; + + // Try to encode the high-precision submode + lowval = (ilum0 + 16) >> 5; + highval = (ilum1 + 16) >> 5; + + lowval = astc::clamp(lowval, 0, 2047); + highval = astc::clamp(highval, 0, 2047); + + v0 = lowval & 0x7F; + v0e = quant_color(quant_level, v0); + v0d = v0e; + + if (v0d < 0x80) + { + lowval = (lowval & ~0x7F) | v0d; + diffval = highval - lowval; + if (diffval >= 0 && diffval <= 15) + { + v1 = ((lowval >> 3) & 0xF0) | diffval; + v1e = quant_color(quant_level, v1); + v1d = v1e; + if ((v1d & 0xF0) == (v1 & 0xF0)) + { + output[0] = static_cast<uint8_t>(v0e); + output[1] = static_cast<uint8_t>(v1e); + return true; + } + } + } + + // Try to encode the low-precision submode + lowval = (ilum0 + 32) >> 6; + highval = (ilum1 + 32) >> 6; + + lowval = astc::clamp(lowval, 0, 1023); + highval = astc::clamp(highval, 0, 1023); + + v0 = (lowval & 0x7F) | 0x80; + v0e = quant_color(quant_level, v0); + v0d = v0e; + if ((v0d & 0x80) == 0) + { + return false; + } + + lowval = (lowval & ~0x7F) | (v0d & 0x7F); + diffval = highval - lowval; + if (diffval < 0 || diffval > 31) + { + return false; + } + + v1 = ((lowval >> 2) & 0xE0) | diffval; + v1e = quant_color(quant_level, v1); + v1d = v1e; + if ((v1d & 0xE0) != (v1 & 0xE0)) + { + return false; + } + + output[0] = static_cast<uint8_t>(v0e); + output[1] = static_cast<uint8_t>(v1e); + return true; +} + +/** + * @brief Quantize a HDR A color using either delta or direct RGBA encoding. + * + * @param alpha0 The input unquantized color0 endpoint. + * @param alpha1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits. + * @param quant_level The quantization level to use. + */ +static void quantize_hdr_alpha( + float alpha0, + float alpha1, + uint8_t output[2], + quant_method quant_level +) { + alpha0 = astc::clamp(alpha0, 0.0f, 65280.0f); + alpha1 = astc::clamp(alpha1, 0.0f, 65280.0f); + + int ialpha0 = astc::flt2int_rtn(alpha0); + int ialpha1 = astc::flt2int_rtn(alpha1); + + int val0, val1, diffval; + int v6, v7; + int v6e, v7e; + int v6d, v7d; + + // Try to encode one of the delta submodes, in decreasing-precision order + for (int i = 2; i >= 0; i--) + { + val0 = (ialpha0 + (128 >> i)) >> (8 - i); + val1 = (ialpha1 + (128 >> i)) >> (8 - i); + + v6 = (val0 & 0x7F) | ((i & 1) << 7); + v6e = quant_color(quant_level, v6); + v6d = v6e; + + if ((v6 ^ v6d) & 0x80) + { + continue; + } + + val0 = (val0 & ~0x7f) | (v6d & 0x7f); + diffval = val1 - val0; + int cutoff = 32 >> i; + int mask = 2 * cutoff - 1; + + if (diffval < -cutoff || diffval >= cutoff) + { + continue; + } + + v7 = ((i & 2) << 6) | ((val0 >> 7) << (6 - i)) | (diffval & mask); + v7e = quant_color(quant_level, v7); + v7d = v7e; + + static const int testbits[3] { 0xE0, 0xF0, 0xF8 }; + + if ((v7 ^ v7d) & testbits[i]) + { + continue; + } + + output[0] = static_cast<uint8_t>(v6e); + output[1] = static_cast<uint8_t>(v7e); + return; + } + + // Could not encode any of the delta modes; instead encode a flat value + val0 = (ialpha0 + 256) >> 9; + val1 = (ialpha1 + 256) >> 9; + v6 = val0 | 0x80; + v7 = val1 | 0x80; + + output[0] = quant_color(quant_level, v6); + output[1] = quant_color(quant_level, v7); + + return; +} + +/** + * @brief Quantize a HDR RGBA color using either delta or direct RGBA encoding. + * + * @param color0 The input unquantized color0 endpoint. + * @param color1 The input unquantized color1 endpoint. + * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits. + * @param quant_level The quantization level to use. + */ +static void quantize_hdr_rgb_alpha( + vfloat4 color0, + vfloat4 color1, + uint8_t output[8], + quant_method quant_level +) { + quantize_hdr_rgb(color0, color1, output, quant_level); + quantize_hdr_alpha(color0.lane<3>(), color1.lane<3>(), output + 6, quant_level); +} + +/* See header for documentation. */ +uint8_t pack_color_endpoints( + vfloat4 color0, + vfloat4 color1, + vfloat4 rgbs_color, + vfloat4 rgbo_color, + int format, + uint8_t* output, + quant_method quant_level +) { + assert(QUANT_6 <= quant_level && quant_level <= QUANT_256); + + // We do not support negative colors + color0 = max(color0, 0.0f); + color1 = max(color1, 0.0f); + + uint8_t retval = 0; + + switch (format) + { + case FMT_RGB: + if (quant_level <= QUANT_160) + { + if (try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level)) + { + retval = FMT_RGB_DELTA; + break; + } + if (try_quantize_rgb_delta(color0, color1, output, quant_level)) + { + retval = FMT_RGB_DELTA; + break; + } + } + if (quant_level < QUANT_256 && try_quantize_rgb_blue_contract(color0, color1, output, quant_level)) + { + retval = FMT_RGB; + break; + } + quantize_rgb(color0, color1, output, quant_level); + retval = FMT_RGB; + break; + + case FMT_RGBA: + if (quant_level <= QUANT_160) + { + if (try_quantize_rgba_delta_blue_contract(color0, color1, output, quant_level)) + { + retval = FMT_RGBA_DELTA; + break; + } + if (try_quantize_rgba_delta(color0, color1, output, quant_level)) + { + retval = FMT_RGBA_DELTA; + break; + } + } + if (quant_level < QUANT_256 && try_quantize_rgba_blue_contract(color0, color1, output, quant_level)) + { + retval = FMT_RGBA; + break; + } + quantize_rgba(color0, color1, output, quant_level); + retval = FMT_RGBA; + break; + + case FMT_RGB_SCALE: + quantize_rgbs(rgbs_color, output, quant_level); + retval = FMT_RGB_SCALE; + break; + + case FMT_HDR_RGB_SCALE: + quantize_hdr_rgbo(rgbo_color, output, quant_level); + retval = FMT_HDR_RGB_SCALE; + break; + + case FMT_HDR_RGB: + quantize_hdr_rgb(color0, color1, output, quant_level); + retval = FMT_HDR_RGB; + break; + + case FMT_RGB_SCALE_ALPHA: + quantize_rgbs_alpha(color0, color1, rgbs_color, output, quant_level); + retval = FMT_RGB_SCALE_ALPHA; + break; + + case FMT_HDR_LUMINANCE_SMALL_RANGE: + case FMT_HDR_LUMINANCE_LARGE_RANGE: + if (try_quantize_hdr_luminance_small_range(color0, color1, output, quant_level)) + { + retval = FMT_HDR_LUMINANCE_SMALL_RANGE; + break; + } + quantize_hdr_luminance_large_range(color0, color1, output, quant_level); + retval = FMT_HDR_LUMINANCE_LARGE_RANGE; + break; + + case FMT_LUMINANCE: + quantize_luminance(color0, color1, output, quant_level); + retval = FMT_LUMINANCE; + break; + + case FMT_LUMINANCE_ALPHA: + if (quant_level <= 18) + { + if (try_quantize_luminance_alpha_delta(color0, color1, output, quant_level)) + { + retval = FMT_LUMINANCE_ALPHA_DELTA; + break; + } + } + quantize_luminance_alpha(color0, color1, output, quant_level); + retval = FMT_LUMINANCE_ALPHA; + break; + + case FMT_HDR_RGB_LDR_ALPHA: + quantize_hdr_rgb_ldr_alpha(color0, color1, output, quant_level); + retval = FMT_HDR_RGB_LDR_ALPHA; + break; + + case FMT_HDR_RGBA: + quantize_hdr_rgb_alpha(color0, color1, output, quant_level); + retval = FMT_HDR_RGBA; + break; + } + + return retval; +} + +#endif diff --git a/thirdparty/astcenc/astcenc_color_unquantize.cpp b/thirdparty/astcenc/astcenc_color_unquantize.cpp new file mode 100644 index 0000000000..d31895a627 --- /dev/null +++ b/thirdparty/astcenc/astcenc_color_unquantize.cpp @@ -0,0 +1,941 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#include <utility> + +/** + * @brief Functions for color unquantization. + */ + +#include "astcenc_internal.h" + +/** + * @brief Un-blue-contract a color. + * + * This function reverses any applied blue contraction. + * + * @param input The input color that has been blue-contracted. + * + * @return The uncontracted color. + */ +static ASTCENC_SIMD_INLINE vint4 uncontract_color( + vint4 input +) { + vmask4 mask(true, true, false, false); + vint4 bc0 = asr<1>(input + input.lane<2>()); + return select(input, bc0, mask); +} + +/** + * @brief Unpack an LDR RGBA color that uses delta encoding. + * + * @param input0 The packed endpoint 0 color. + * @param input1 The packed endpoint 1 color deltas. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void rgba_delta_unpack( + vint4 input0, + vint4 input1, + vint4& output0, + vint4& output1 +) { + // Apply bit transfer + bit_transfer_signed(input1, input0); + + // Apply blue-uncontraction if needed + int rgb_sum = hadd_rgb_s(input1); + input1 = input1 + input0; + if (rgb_sum < 0) + { + input0 = uncontract_color(input0); + input1 = uncontract_color(input1); + std::swap(input0, input1); + } + + output0 = clamp(0, 255, input0); + output1 = clamp(0, 255, input1); +} + +/** + * @brief Unpack an LDR RGB color that uses delta encoding. + * + * Output alpha set to 255. + * + * @param input0 The packed endpoint 0 color. + * @param input1 The packed endpoint 1 color deltas. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void rgb_delta_unpack( + vint4 input0, + vint4 input1, + vint4& output0, + vint4& output1 +) { + rgba_delta_unpack(input0, input1, output0, output1); + output0.set_lane<3>(255); + output1.set_lane<3>(255); +} + +/** + * @brief Unpack an LDR RGBA color that uses direct encoding. + * + * @param input0 The packed endpoint 0 color. + * @param input1 The packed endpoint 1 color. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void rgba_unpack( + vint4 input0, + vint4 input1, + vint4& output0, + vint4& output1 +) { + // Apply blue-uncontraction if needed + if (hadd_rgb_s(input0) > hadd_rgb_s(input1)) + { + input0 = uncontract_color(input0); + input1 = uncontract_color(input1); + std::swap(input0, input1); + } + + output0 = input0; + output1 = input1; +} + +/** + * @brief Unpack an LDR RGB color that uses direct encoding. + * + * Output alpha set to 255. + * + * @param input0 The packed endpoint 0 color. + * @param input1 The packed endpoint 1 color. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void rgb_unpack( + vint4 input0, + vint4 input1, + vint4& output0, + vint4& output1 +) { + rgba_unpack(input0, input1, output0, output1); + output0.set_lane<3>(255); + output1.set_lane<3>(255); +} + +/** + * @brief Unpack an LDR RGBA color that uses scaled encoding. + * + * Note only the RGB channels use the scaled encoding, alpha uses direct. + * + * @param input0 The packed endpoint 0 color. + * @param alpha1 The packed endpoint 1 alpha value. + * @param scale The packed quantized scale. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void rgb_scale_alpha_unpack( + vint4 input0, + uint8_t alpha1, + uint8_t scale, + vint4& output0, + vint4& output1 +) { + output1 = input0; + output1.set_lane<3>(alpha1); + + output0 = asr<8>(input0 * scale); + output0.set_lane<3>(input0.lane<3>()); +} + +/** + * @brief Unpack an LDR RGB color that uses scaled encoding. + * + * Output alpha is 255. + * + * @param input0 The packed endpoint 0 color. + * @param scale The packed scale. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void rgb_scale_unpack( + vint4 input0, + int scale, + vint4& output0, + vint4& output1 +) { + output1 = input0; + output1.set_lane<3>(255); + + output0 = asr<8>(input0 * scale); + output0.set_lane<3>(255); +} + +/** + * @brief Unpack an LDR L color that uses direct encoding. + * + * Output alpha is 255. + * + * @param input The packed endpoints. + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void luminance_unpack( + const uint8_t input[2], + vint4& output0, + vint4& output1 +) { + int lum0 = input[0]; + int lum1 = input[1]; + output0 = vint4(lum0, lum0, lum0, 255); + output1 = vint4(lum1, lum1, lum1, 255); +} + +/** + * @brief Unpack an LDR L color that uses delta encoding. + * + * Output alpha is 255. + * + * @param input The packed endpoints (L0, L1). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void luminance_delta_unpack( + const uint8_t input[2], + vint4& output0, + vint4& output1 +) { + int v0 = input[0]; + int v1 = input[1]; + int l0 = (v0 >> 2) | (v1 & 0xC0); + int l1 = l0 + (v1 & 0x3F); + + l1 = astc::min(l1, 255); + + output0 = vint4(l0, l0, l0, 255); + output1 = vint4(l1, l1, l1, 255); +} + +/** + * @brief Unpack an LDR LA color that uses direct encoding. + * + * @param input The packed endpoints (L0, L1, A0, A1). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void luminance_alpha_unpack( + const uint8_t input[4], + vint4& output0, + vint4& output1 +) { + int lum0 = input[0]; + int lum1 = input[1]; + int alpha0 = input[2]; + int alpha1 = input[3]; + output0 = vint4(lum0, lum0, lum0, alpha0); + output1 = vint4(lum1, lum1, lum1, alpha1); +} + +/** + * @brief Unpack an LDR LA color that uses delta encoding. + * + * @param input The packed endpoints (L0, L1, A0, A1). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void luminance_alpha_delta_unpack( + const uint8_t input[4], + vint4& output0, + vint4& output1 +) { + int lum0 = input[0]; + int lum1 = input[1]; + int alpha0 = input[2]; + int alpha1 = input[3]; + + lum0 |= (lum1 & 0x80) << 1; + alpha0 |= (alpha1 & 0x80) << 1; + lum1 &= 0x7F; + alpha1 &= 0x7F; + + if (lum1 & 0x40) + { + lum1 -= 0x80; + } + + if (alpha1 & 0x40) + { + alpha1 -= 0x80; + } + + lum0 >>= 1; + lum1 >>= 1; + alpha0 >>= 1; + alpha1 >>= 1; + lum1 += lum0; + alpha1 += alpha0; + + lum1 = astc::clamp(lum1, 0, 255); + alpha1 = astc::clamp(alpha1, 0, 255); + + output0 = vint4(lum0, lum0, lum0, alpha0); + output1 = vint4(lum1, lum1, lum1, alpha1); +} + +/** + * @brief Unpack an HDR RGB + offset encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_rgbo_unpack( + const uint8_t input[4], + vint4& output0, + vint4& output1 +) { + int v0 = input[0]; + int v1 = input[1]; + int v2 = input[2]; + int v3 = input[3]; + + int modeval = ((v0 & 0xC0) >> 6) | (((v1 & 0x80) >> 7) << 2) | (((v2 & 0x80) >> 7) << 3); + + int majcomp; + int mode; + if ((modeval & 0xC) != 0xC) + { + majcomp = modeval >> 2; + mode = modeval & 3; + } + else if (modeval != 0xF) + { + majcomp = modeval & 3; + mode = 4; + } + else + { + majcomp = 0; + mode = 5; + } + + int red = v0 & 0x3F; + int green = v1 & 0x1F; + int blue = v2 & 0x1F; + int scale = v3 & 0x1F; + + int bit0 = (v1 >> 6) & 1; + int bit1 = (v1 >> 5) & 1; + int bit2 = (v2 >> 6) & 1; + int bit3 = (v2 >> 5) & 1; + int bit4 = (v3 >> 7) & 1; + int bit5 = (v3 >> 6) & 1; + int bit6 = (v3 >> 5) & 1; + + int ohcomp = 1 << mode; + + if (ohcomp & 0x30) + green |= bit0 << 6; + if (ohcomp & 0x3A) + green |= bit1 << 5; + if (ohcomp & 0x30) + blue |= bit2 << 6; + if (ohcomp & 0x3A) + blue |= bit3 << 5; + + if (ohcomp & 0x3D) + scale |= bit6 << 5; + if (ohcomp & 0x2D) + scale |= bit5 << 6; + if (ohcomp & 0x04) + scale |= bit4 << 7; + + if (ohcomp & 0x3B) + red |= bit4 << 6; + if (ohcomp & 0x04) + red |= bit3 << 6; + + if (ohcomp & 0x10) + red |= bit5 << 7; + if (ohcomp & 0x0F) + red |= bit2 << 7; + + if (ohcomp & 0x05) + red |= bit1 << 8; + if (ohcomp & 0x0A) + red |= bit0 << 8; + + if (ohcomp & 0x05) + red |= bit0 << 9; + if (ohcomp & 0x02) + red |= bit6 << 9; + + if (ohcomp & 0x01) + red |= bit3 << 10; + if (ohcomp & 0x02) + red |= bit5 << 10; + + // expand to 12 bits. + static const int shamts[6] { 1, 1, 2, 3, 4, 5 }; + int shamt = shamts[mode]; + red <<= shamt; + green <<= shamt; + blue <<= shamt; + scale <<= shamt; + + // on modes 0 to 4, the values stored for "green" and "blue" are differentials, + // not absolute values. + if (mode != 5) + { + green = red - green; + blue = red - blue; + } + + // switch around components. + int temp; + switch (majcomp) + { + case 1: + temp = red; + red = green; + green = temp; + break; + case 2: + temp = red; + red = blue; + blue = temp; + break; + default: + break; + } + + int red0 = red - scale; + int green0 = green - scale; + int blue0 = blue - scale; + + // clamp to [0,0xFFF]. + if (red < 0) + red = 0; + if (green < 0) + green = 0; + if (blue < 0) + blue = 0; + + if (red0 < 0) + red0 = 0; + if (green0 < 0) + green0 = 0; + if (blue0 < 0) + blue0 = 0; + + output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800); + output1 = vint4(red << 4, green << 4, blue << 4, 0x7800); +} + +/** + * @brief Unpack an HDR RGB direct encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_rgb_unpack( + const uint8_t input[6], + vint4& output0, + vint4& output1 +) { + + int v0 = input[0]; + int v1 = input[1]; + int v2 = input[2]; + int v3 = input[3]; + int v4 = input[4]; + int v5 = input[5]; + + // extract all the fixed-placement bitfields + int modeval = ((v1 & 0x80) >> 7) | (((v2 & 0x80) >> 7) << 1) | (((v3 & 0x80) >> 7) << 2); + + int majcomp = ((v4 & 0x80) >> 7) | (((v5 & 0x80) >> 7) << 1); + + if (majcomp == 3) + { + output0 = vint4(v0 << 8, v2 << 8, (v4 & 0x7F) << 9, 0x7800); + output1 = vint4(v1 << 8, v3 << 8, (v5 & 0x7F) << 9, 0x7800); + return; + } + + int a = v0 | ((v1 & 0x40) << 2); + int b0 = v2 & 0x3f; + int b1 = v3 & 0x3f; + int c = v1 & 0x3f; + int d0 = v4 & 0x7f; + int d1 = v5 & 0x7f; + + // get hold of the number of bits in 'd0' and 'd1' + static const int dbits_tab[8] { 7, 6, 7, 6, 5, 6, 5, 6 }; + int dbits = dbits_tab[modeval]; + + // extract six variable-placement bits + int bit0 = (v2 >> 6) & 1; + int bit1 = (v3 >> 6) & 1; + int bit2 = (v4 >> 6) & 1; + int bit3 = (v5 >> 6) & 1; + int bit4 = (v4 >> 5) & 1; + int bit5 = (v5 >> 5) & 1; + + // and prepend the variable-placement bits depending on mode. + int ohmod = 1 << modeval; // one-hot-mode + if (ohmod & 0xA4) + a |= bit0 << 9; + if (ohmod & 0x8) + a |= bit2 << 9; + if (ohmod & 0x50) + a |= bit4 << 9; + + if (ohmod & 0x50) + a |= bit5 << 10; + if (ohmod & 0xA0) + a |= bit1 << 10; + + if (ohmod & 0xC0) + a |= bit2 << 11; + + if (ohmod & 0x4) + c |= bit1 << 6; + if (ohmod & 0xE8) + c |= bit3 << 6; + + if (ohmod & 0x20) + c |= bit2 << 7; + + if (ohmod & 0x5B) + { + b0 |= bit0 << 6; + b1 |= bit1 << 6; + } + + if (ohmod & 0x12) + { + b0 |= bit2 << 7; + b1 |= bit3 << 7; + } + + if (ohmod & 0xAF) + { + d0 |= bit4 << 5; + d1 |= bit5 << 5; + } + + if (ohmod & 0x5) + { + d0 |= bit2 << 6; + d1 |= bit3 << 6; + } + + // sign-extend 'd0' and 'd1' + // note: this code assumes that signed right-shift actually sign-fills, not zero-fills. + int32_t d0x = d0; + int32_t d1x = d1; + int sx_shamt = 32 - dbits; + d0x <<= sx_shamt; + d0x >>= sx_shamt; + d1x <<= sx_shamt; + d1x >>= sx_shamt; + d0 = d0x; + d1 = d1x; + + // expand all values to 12 bits, with left-shift as needed. + int val_shamt = (modeval >> 1) ^ 3; + a <<= val_shamt; + b0 <<= val_shamt; + b1 <<= val_shamt; + c <<= val_shamt; + d0 <<= val_shamt; + d1 <<= val_shamt; + + // then compute the actual color values. + int red1 = a; + int green1 = a - b0; + int blue1 = a - b1; + int red0 = a - c; + int green0 = a - b0 - c - d0; + int blue0 = a - b1 - c - d1; + + // clamp the color components to [0,2^12 - 1] + red0 = astc::clamp(red0, 0, 4095); + green0 = astc::clamp(green0, 0, 4095); + blue0 = astc::clamp(blue0, 0, 4095); + + red1 = astc::clamp(red1, 0, 4095); + green1 = astc::clamp(green1, 0, 4095); + blue1 = astc::clamp(blue1, 0, 4095); + + // switch around the color components + int temp0, temp1; + switch (majcomp) + { + case 1: // switch around red and green + temp0 = red0; + temp1 = red1; + red0 = green0; + red1 = green1; + green0 = temp0; + green1 = temp1; + break; + case 2: // switch around red and blue + temp0 = red0; + temp1 = red1; + red0 = blue0; + red1 = blue1; + blue0 = temp0; + blue1 = temp1; + break; + case 0: // no switch + break; + } + + output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800); + output1 = vint4(red1 << 4, green1 << 4, blue1 << 4, 0x7800); +} + +/** + * @brief Unpack an HDR RGB + LDR A direct encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_rgb_ldr_alpha_unpack( + const uint8_t input[8], + vint4& output0, + vint4& output1 +) { + hdr_rgb_unpack(input, output0, output1); + + int v6 = input[6]; + int v7 = input[7]; + output0.set_lane<3>(v6); + output1.set_lane<3>(v7); +} + +/** + * @brief Unpack an HDR L (small range) direct encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_luminance_small_range_unpack( + const uint8_t input[2], + vint4& output0, + vint4& output1 +) { + int v0 = input[0]; + int v1 = input[1]; + + int y0, y1; + if (v0 & 0x80) + { + y0 = ((v1 & 0xE0) << 4) | ((v0 & 0x7F) << 2); + y1 = (v1 & 0x1F) << 2; + } + else + { + y0 = ((v1 & 0xF0) << 4) | ((v0 & 0x7F) << 1); + y1 = (v1 & 0xF) << 1; + } + + y1 += y0; + if (y1 > 0xFFF) + { + y1 = 0xFFF; + } + + output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800); + output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800); +} + +/** + * @brief Unpack an HDR L (large range) direct encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_luminance_large_range_unpack( + const uint8_t input[2], + vint4& output0, + vint4& output1 +) { + int v0 = input[0]; + int v1 = input[1]; + + int y0, y1; + if (v1 >= v0) + { + y0 = v0 << 4; + y1 = v1 << 4; + } + else + { + y0 = (v1 << 4) + 8; + y1 = (v0 << 4) - 8; + } + + output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800); + output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800); +} + +/** + * @brief Unpack an HDR A direct encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_alpha_unpack( + const uint8_t input[2], + int& output0, + int& output1 +) { + + int v6 = input[0]; + int v7 = input[1]; + + int selector = ((v6 >> 7) & 1) | ((v7 >> 6) & 2); + v6 &= 0x7F; + v7 &= 0x7F; + if (selector == 3) + { + output0 = v6 << 5; + output1 = v7 << 5; + } + else + { + v6 |= (v7 << (selector + 1)) & 0x780; + v7 &= (0x3f >> selector); + v7 ^= 32 >> selector; + v7 -= 32 >> selector; + v6 <<= (4 - selector); + v7 <<= (4 - selector); + v7 += v6; + + if (v7 < 0) + { + v7 = 0; + } + else if (v7 > 0xFFF) + { + v7 = 0xFFF; + } + + output0 = v6; + output1 = v7; + } + + output0 <<= 4; + output1 <<= 4; +} + +/** + * @brief Unpack an HDR RGBA direct encoding. + * + * @param input The packed endpoints (packed and modal). + * @param[out] output0 The unpacked endpoint 0 color. + * @param[out] output1 The unpacked endpoint 1 color. + */ +static void hdr_rgb_hdr_alpha_unpack( + const uint8_t input[8], + vint4& output0, + vint4& output1 +) { + hdr_rgb_unpack(input, output0, output1); + + int alpha0, alpha1; + hdr_alpha_unpack(input + 6, alpha0, alpha1); + + output0.set_lane<3>(alpha0); + output1.set_lane<3>(alpha1); +} + +/* See header for documentation. */ +void unpack_color_endpoints( + astcenc_profile decode_mode, + int format, + const uint8_t* input, + bool& rgb_hdr, + bool& alpha_hdr, + vint4& output0, + vint4& output1 +) { + // Assume no NaNs and LDR endpoints unless set later + rgb_hdr = false; + alpha_hdr = false; + + bool alpha_hdr_default = false; + + switch (format) + { + case FMT_LUMINANCE: + luminance_unpack(input, output0, output1); + break; + + case FMT_LUMINANCE_DELTA: + luminance_delta_unpack(input, output0, output1); + break; + + case FMT_HDR_LUMINANCE_SMALL_RANGE: + rgb_hdr = true; + alpha_hdr_default = true; + hdr_luminance_small_range_unpack(input, output0, output1); + break; + + case FMT_HDR_LUMINANCE_LARGE_RANGE: + rgb_hdr = true; + alpha_hdr_default = true; + hdr_luminance_large_range_unpack(input, output0, output1); + break; + + case FMT_LUMINANCE_ALPHA: + luminance_alpha_unpack(input, output0, output1); + break; + + case FMT_LUMINANCE_ALPHA_DELTA: + luminance_alpha_delta_unpack(input, output0, output1); + break; + + case FMT_RGB_SCALE: + { + vint4 input0q(input[0], input[1], input[2], 0); + uint8_t scale = input[3]; + rgb_scale_unpack(input0q, scale, output0, output1); + } + break; + + case FMT_RGB_SCALE_ALPHA: + { + vint4 input0q(input[0], input[1], input[2], input[4]); + uint8_t alpha1q = input[5]; + uint8_t scaleq = input[3]; + rgb_scale_alpha_unpack(input0q, alpha1q, scaleq, output0, output1); + } + break; + + case FMT_HDR_RGB_SCALE: + rgb_hdr = true; + alpha_hdr_default = true; + hdr_rgbo_unpack(input, output0, output1); + break; + + case FMT_RGB: + { + vint4 input0q(input[0], input[2], input[4], 0); + vint4 input1q(input[1], input[3], input[5], 0); + rgb_unpack(input0q, input1q, output0, output1); + } + break; + + case FMT_RGB_DELTA: + { + vint4 input0q(input[0], input[2], input[4], 0); + vint4 input1q(input[1], input[3], input[5], 0); + rgb_delta_unpack(input0q, input1q, output0, output1); + } + break; + + case FMT_HDR_RGB: + rgb_hdr = true; + alpha_hdr_default = true; + hdr_rgb_unpack(input, output0, output1); + break; + + case FMT_RGBA: + { + vint4 input0q(input[0], input[2], input[4], input[6]); + vint4 input1q(input[1], input[3], input[5], input[7]); + rgba_unpack(input0q, input1q, output0, output1); + } + break; + + case FMT_RGBA_DELTA: + { + vint4 input0q(input[0], input[2], input[4], input[6]); + vint4 input1q(input[1], input[3], input[5], input[7]); + rgba_delta_unpack(input0q, input1q, output0, output1); + } + break; + + case FMT_HDR_RGB_LDR_ALPHA: + rgb_hdr = true; + hdr_rgb_ldr_alpha_unpack(input, output0, output1); + break; + + case FMT_HDR_RGBA: + rgb_hdr = true; + alpha_hdr = true; + hdr_rgb_hdr_alpha_unpack(input, output0, output1); + break; + } + + // Assign a correct default alpha + if (alpha_hdr_default) + { + if (decode_mode == ASTCENC_PRF_HDR) + { + output0.set_lane<3>(0x7800); + output1.set_lane<3>(0x7800); + alpha_hdr = true; + } + else + { + output0.set_lane<3>(0x00FF); + output1.set_lane<3>(0x00FF); + alpha_hdr = false; + } + } + + vint4 ldr_scale(257); + vint4 hdr_scale(1); + vint4 output_scale = ldr_scale; + + // An LDR profile image + if ((decode_mode == ASTCENC_PRF_LDR) || + (decode_mode == ASTCENC_PRF_LDR_SRGB)) + { + // Also matches HDR alpha, as cannot have HDR alpha without HDR RGB + if (rgb_hdr == true) + { + output0 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00); + output1 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00); + output_scale = hdr_scale; + + rgb_hdr = false; + alpha_hdr = false; + } + } + // An HDR profile image + else + { + vmask4 hdr_lanes(rgb_hdr, rgb_hdr, rgb_hdr, alpha_hdr); + output_scale = select(ldr_scale, hdr_scale, hdr_lanes); + } + + output0 = output0 * output_scale; + output1 = output1 * output_scale; +} diff --git a/thirdparty/astcenc/astcenc_compress_symbolic.cpp b/thirdparty/astcenc/astcenc_compress_symbolic.cpp new file mode 100644 index 0000000000..afb76246e7 --- /dev/null +++ b/thirdparty/astcenc/astcenc_compress_symbolic.cpp @@ -0,0 +1,1455 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions to compress a symbolic block. + */ + +#include "astcenc_internal.h" +#include "astcenc_diagnostic_trace.h" + +#include <cassert> + +/** + * @brief Merge two planes of endpoints into a single vector. + * + * @param ep_plane1 The endpoints for plane 1. + * @param ep_plane2 The endpoints for plane 2. + * @param component_plane2 The color component for plane 2. + * @param[out] result The merged output. + */ +static void merge_endpoints( + const endpoints& ep_plane1, + const endpoints& ep_plane2, + unsigned int component_plane2, + endpoints& result +) { + unsigned int partition_count = ep_plane1.partition_count; + assert(partition_count == 1); + + vmask4 sep_mask = vint4::lane_id() == vint4(component_plane2); + + result.partition_count = partition_count; + result.endpt0[0] = select(ep_plane1.endpt0[0], ep_plane2.endpt0[0], sep_mask); + result.endpt1[0] = select(ep_plane1.endpt1[0], ep_plane2.endpt1[0], sep_mask); +} + +/** + * @brief Attempt to improve weights given a chosen configuration. + * + * Given a fixed weight grid decimation and weight value quantization, iterate over all weights (per + * partition and per plane) and attempt to improve image quality by moving each weight up by one or + * down by one quantization step. + * + * This is a specialized function which only supports operating on undecimated weight grids, + * therefore primarily improving the performance of 4x4 and 5x5 blocks where grid decimation + * is needed less often. + * + * @param decode_mode The decode mode (LDR, HDR). + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param[out] scb The symbolic compressed block output. + */ +static bool realign_weights_undecimated( + astcenc_profile decode_mode, + const block_size_descriptor& bsd, + const image_block& blk, + symbolic_compressed_block& scb +) { + // Get the partition descriptor + unsigned int partition_count = scb.partition_count; + const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index); + + // Get the quantization table + const block_mode& bm = bsd.get_block_mode(scb.block_mode); + unsigned int weight_quant_level = bm.quant_mode; + const quant_and_transfer_table& qat = quant_and_xfer_tables[weight_quant_level]; + + unsigned int max_plane = bm.is_dual_plane; + int plane2_component = scb.plane2_component; + vmask4 plane_mask = vint4::lane_id() == vint4(plane2_component); + + // Decode the color endpoints + bool rgb_hdr; + bool alpha_hdr; + vint4 endpnt0[BLOCK_MAX_PARTITIONS]; + vint4 endpnt1[BLOCK_MAX_PARTITIONS]; + vfloat4 endpnt0f[BLOCK_MAX_PARTITIONS]; + vfloat4 offset[BLOCK_MAX_PARTITIONS]; + + promise(partition_count > 0); + + for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++) + { + unpack_color_endpoints(decode_mode, + scb.color_formats[pa_idx], + scb.color_values[pa_idx], + rgb_hdr, alpha_hdr, + endpnt0[pa_idx], + endpnt1[pa_idx]); + } + + uint8_t* dec_weights_uquant = scb.weights; + bool adjustments = false; + + // For each plane and partition ... + for (unsigned int pl_idx = 0; pl_idx <= max_plane; pl_idx++) + { + for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++) + { + // Compute the endpoint delta for all components in current plane + vint4 epd = endpnt1[pa_idx] - endpnt0[pa_idx]; + epd = select(epd, vint4::zero(), plane_mask); + + endpnt0f[pa_idx] = int_to_float(endpnt0[pa_idx]); + offset[pa_idx] = int_to_float(epd) * (1.0f / 64.0f); + } + + // For each weight compute previous, current, and next errors + promise(bsd.texel_count > 0); + for (unsigned int texel = 0; texel < bsd.texel_count; texel++) + { + int uqw = dec_weights_uquant[texel]; + + uint32_t prev_and_next = qat.prev_next_values[uqw]; + int uqw_down = prev_and_next & 0xFF; + int uqw_up = (prev_and_next >> 8) & 0xFF; + + // Interpolate the colors to create the diffs + float weight_base = static_cast<float>(uqw); + float weight_down = static_cast<float>(uqw_down - uqw); + float weight_up = static_cast<float>(uqw_up - uqw); + + unsigned int partition = pi.partition_of_texel[texel]; + vfloat4 color_offset = offset[partition]; + vfloat4 color_base = endpnt0f[partition]; + + vfloat4 color = color_base + color_offset * weight_base; + vfloat4 orig_color = blk.texel(texel); + vfloat4 error_weight = blk.channel_weight; + + vfloat4 color_diff = color - orig_color; + vfloat4 color_diff_down = color_diff + color_offset * weight_down; + vfloat4 color_diff_up = color_diff + color_offset * weight_up; + + float error_base = dot_s(color_diff * color_diff, error_weight); + float error_down = dot_s(color_diff_down * color_diff_down, error_weight); + float error_up = dot_s(color_diff_up * color_diff_up, error_weight); + + // Check if the prev or next error is better, and if so use it + if ((error_up < error_base) && (error_up < error_down) && (uqw < 64)) + { + dec_weights_uquant[texel] = static_cast<uint8_t>(uqw_up); + adjustments = true; + } + else if ((error_down < error_base) && (uqw > 0)) + { + dec_weights_uquant[texel] = static_cast<uint8_t>(uqw_down); + adjustments = true; + } + } + + // Prepare iteration for plane 2 + dec_weights_uquant += WEIGHTS_PLANE2_OFFSET; + plane_mask = ~plane_mask; + } + + return adjustments; +} + +/** + * @brief Attempt to improve weights given a chosen configuration. + * + * Given a fixed weight grid decimation and weight value quantization, iterate over all weights (per + * partition and per plane) and attempt to improve image quality by moving each weight up by one or + * down by one quantization step. + * + * @param decode_mode The decode mode (LDR, HDR). + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param[out] scb The symbolic compressed block output. + */ +static bool realign_weights_decimated( + astcenc_profile decode_mode, + const block_size_descriptor& bsd, + const image_block& blk, + symbolic_compressed_block& scb +) { + // Get the partition descriptor + unsigned int partition_count = scb.partition_count; + const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index); + + // Get the quantization table + const block_mode& bm = bsd.get_block_mode(scb.block_mode); + unsigned int weight_quant_level = bm.quant_mode; + const quant_and_transfer_table& qat = quant_and_xfer_tables[weight_quant_level]; + + // Get the decimation table + const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode); + unsigned int weight_count = di.weight_count; + assert(weight_count != bsd.texel_count); + + unsigned int max_plane = bm.is_dual_plane; + int plane2_component = scb.plane2_component; + vmask4 plane_mask = vint4::lane_id() == vint4(plane2_component); + + // Decode the color endpoints + bool rgb_hdr; + bool alpha_hdr; + vint4 endpnt0[BLOCK_MAX_PARTITIONS]; + vint4 endpnt1[BLOCK_MAX_PARTITIONS]; + vfloat4 endpnt0f[BLOCK_MAX_PARTITIONS]; + vfloat4 offset[BLOCK_MAX_PARTITIONS]; + + promise(partition_count > 0); + promise(weight_count > 0); + + for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++) + { + unpack_color_endpoints(decode_mode, + scb.color_formats[pa_idx], + scb.color_values[pa_idx], + rgb_hdr, alpha_hdr, + endpnt0[pa_idx], + endpnt1[pa_idx]); + } + + uint8_t* dec_weights_uquant = scb.weights; + bool adjustments = false; + + // For each plane and partition ... + for (unsigned int pl_idx = 0; pl_idx <= max_plane; pl_idx++) + { + for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++) + { + // Compute the endpoint delta for all components in current plane + vint4 epd = endpnt1[pa_idx] - endpnt0[pa_idx]; + epd = select(epd, vint4::zero(), plane_mask); + + endpnt0f[pa_idx] = int_to_float(endpnt0[pa_idx]); + offset[pa_idx] = int_to_float(epd) * (1.0f / 64.0f); + } + + // Create an unquantized weight grid for this decimation level + alignas(ASTCENC_VECALIGN) float uq_weightsf[BLOCK_MAX_WEIGHTS]; + for (unsigned int we_idx = 0; we_idx < weight_count; we_idx += ASTCENC_SIMD_WIDTH) + { + vint unquant_value(dec_weights_uquant + we_idx); + vfloat unquant_valuef = int_to_float(unquant_value); + storea(unquant_valuef, uq_weightsf + we_idx); + } + + // For each weight compute previous, current, and next errors + for (unsigned int we_idx = 0; we_idx < weight_count; we_idx++) + { + int uqw = dec_weights_uquant[we_idx]; + uint32_t prev_and_next = qat.prev_next_values[uqw]; + + float uqw_base = uq_weightsf[we_idx]; + float uqw_down = static_cast<float>(prev_and_next & 0xFF); + float uqw_up = static_cast<float>((prev_and_next >> 8) & 0xFF); + + float uqw_diff_down = uqw_down - uqw_base; + float uqw_diff_up = uqw_up - uqw_base; + + vfloat4 error_basev = vfloat4::zero(); + vfloat4 error_downv = vfloat4::zero(); + vfloat4 error_upv = vfloat4::zero(); + + // Interpolate the colors to create the diffs + unsigned int texels_to_evaluate = di.weight_texel_count[we_idx]; + promise(texels_to_evaluate > 0); + for (unsigned int te_idx = 0; te_idx < texels_to_evaluate; te_idx++) + { + unsigned int texel = di.weight_texels_tr[te_idx][we_idx]; + + float tw_base = di.texel_contrib_for_weight[te_idx][we_idx]; + + float weight_base = (uq_weightsf[di.texel_weights_tr[0][texel]] * di.texel_weight_contribs_float_tr[0][texel] + + uq_weightsf[di.texel_weights_tr[1][texel]] * di.texel_weight_contribs_float_tr[1][texel]) + + (uq_weightsf[di.texel_weights_tr[2][texel]] * di.texel_weight_contribs_float_tr[2][texel] + + uq_weightsf[di.texel_weights_tr[3][texel]] * di.texel_weight_contribs_float_tr[3][texel]); + + // Ideally this is integer rounded, but IQ gain it isn't worth the overhead + // float weight = astc::flt_rd(weight_base + 0.5f); + // float weight_down = astc::flt_rd(weight_base + 0.5f + uqw_diff_down * tw_base) - weight; + // float weight_up = astc::flt_rd(weight_base + 0.5f + uqw_diff_up * tw_base) - weight; + float weight_down = weight_base + uqw_diff_down * tw_base - weight_base; + float weight_up = weight_base + uqw_diff_up * tw_base - weight_base; + + unsigned int partition = pi.partition_of_texel[texel]; + vfloat4 color_offset = offset[partition]; + vfloat4 color_base = endpnt0f[partition]; + + vfloat4 color = color_base + color_offset * weight_base; + vfloat4 orig_color = blk.texel(texel); + + vfloat4 color_diff = color - orig_color; + vfloat4 color_down_diff = color_diff + color_offset * weight_down; + vfloat4 color_up_diff = color_diff + color_offset * weight_up; + + error_basev += color_diff * color_diff; + error_downv += color_down_diff * color_down_diff; + error_upv += color_up_diff * color_up_diff; + } + + vfloat4 error_weight = blk.channel_weight; + float error_base = hadd_s(error_basev * error_weight); + float error_down = hadd_s(error_downv * error_weight); + float error_up = hadd_s(error_upv * error_weight); + + // Check if the prev or next error is better, and if so use it + if ((error_up < error_base) && (error_up < error_down) && (uqw < 64)) + { + uq_weightsf[we_idx] = uqw_up; + dec_weights_uquant[we_idx] = static_cast<uint8_t>(uqw_up); + adjustments = true; + } + else if ((error_down < error_base) && (uqw > 0)) + { + uq_weightsf[we_idx] = uqw_down; + dec_weights_uquant[we_idx] = static_cast<uint8_t>(uqw_down); + adjustments = true; + } + } + + // Prepare iteration for plane 2 + dec_weights_uquant += WEIGHTS_PLANE2_OFFSET; + plane_mask = ~plane_mask; + } + + return adjustments; +} + +/** + * @brief Compress a block using a chosen partitioning and 1 plane of weights. + * + * @param config The compressor configuration. + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param only_always True if we only use "always" percentile block modes. + * @param tune_errorval_threshold The error value threshold. + * @param partition_count The partition count. + * @param partition_index The partition index if @c partition_count is 2-4. + * @param[out] scb The symbolic compressed block output. + * @param[out] tmpbuf The quantized weights for plane 1. + */ +static float compress_symbolic_block_for_partition_1plane( + const astcenc_config& config, + const block_size_descriptor& bsd, + const image_block& blk, + bool only_always, + float tune_errorval_threshold, + unsigned int partition_count, + unsigned int partition_index, + symbolic_compressed_block& scb, + compression_working_buffers& tmpbuf, + int quant_limit +) { + promise(partition_count > 0); + promise(config.tune_candidate_limit > 0); + promise(config.tune_refinement_limit > 0); + + int max_weight_quant = astc::min(static_cast<int>(QUANT_32), quant_limit); + + auto compute_difference = &compute_symbolic_block_difference_1plane; + if ((partition_count == 1) && !(config.flags & ASTCENC_FLG_MAP_RGBM)) + { + compute_difference = &compute_symbolic_block_difference_1plane_1partition; + } + + const auto& pi = bsd.get_partition_info(partition_count, partition_index); + + // Compute ideal weights and endpoint colors, with no quantization or decimation + endpoints_and_weights& ei = tmpbuf.ei1; + compute_ideal_colors_and_weights_1plane(blk, pi, ei); + + // Compute ideal weights and endpoint colors for every decimation + float* dec_weights_ideal = tmpbuf.dec_weights_ideal; + uint8_t* dec_weights_uquant = tmpbuf.dec_weights_uquant; + + // For each decimation mode, compute an ideal set of weights with no quantization + unsigned int max_decimation_modes = only_always ? bsd.decimation_mode_count_always + : bsd.decimation_mode_count_selected; + promise(max_decimation_modes > 0); + for (unsigned int i = 0; i < max_decimation_modes; i++) + { + const auto& dm = bsd.get_decimation_mode(i); + if (!dm.is_ref_1_plane(static_cast<quant_method>(max_weight_quant))) + { + continue; + } + + const auto& di = bsd.get_decimation_info(i); + + compute_ideal_weights_for_decimation( + ei, + di, + dec_weights_ideal + i * BLOCK_MAX_WEIGHTS); + } + + // Compute maximum colors for the endpoints and ideal weights, then for each endpoint and ideal + // weight pair, compute the smallest weight that will result in a color value greater than 1 + vfloat4 min_ep(10.0f); + for (unsigned int i = 0; i < partition_count; i++) + { + vfloat4 ep = (vfloat4(1.0f) - ei.ep.endpt0[i]) / (ei.ep.endpt1[i] - ei.ep.endpt0[i]); + + vmask4 use_ep = (ep > vfloat4(0.5f)) & (ep < min_ep); + min_ep = select(min_ep, ep, use_ep); + } + + float min_wt_cutoff = hmin_s(min_ep); + + // For each mode, use the angular method to compute a shift + compute_angular_endpoints_1plane( + only_always, bsd, dec_weights_ideal, max_weight_quant, tmpbuf); + + float* weight_low_value = tmpbuf.weight_low_value1; + float* weight_high_value = tmpbuf.weight_high_value1; + int8_t* qwt_bitcounts = tmpbuf.qwt_bitcounts; + float* qwt_errors = tmpbuf.qwt_errors; + + // For each mode (which specifies a decimation and a quantization): + // * Compute number of bits needed for the quantized weights + // * Generate an optimized set of quantized weights + // * Compute quantization errors for the mode + + + static const int8_t free_bits_for_partition_count[4] { + 115 - 4, 111 - 4 - PARTITION_INDEX_BITS, 108 - 4 - PARTITION_INDEX_BITS, 105 - 4 - PARTITION_INDEX_BITS + }; + + unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always + : bsd.block_mode_count_1plane_selected; + promise(max_block_modes > 0); + for (unsigned int i = 0; i < max_block_modes; i++) + { + const block_mode& bm = bsd.block_modes[i]; + + if (bm.quant_mode > max_weight_quant) + { + qwt_errors[i] = 1e38f; + continue; + } + + assert(!bm.is_dual_plane); + int bitcount = free_bits_for_partition_count[partition_count - 1] - bm.weight_bits; + if (bitcount <= 0) + { + qwt_errors[i] = 1e38f; + continue; + } + + if (weight_high_value[i] > 1.02f * min_wt_cutoff) + { + weight_high_value[i] = 1.0f; + } + + int decimation_mode = bm.decimation_mode; + const auto& di = bsd.get_decimation_info(decimation_mode); + + qwt_bitcounts[i] = static_cast<int8_t>(bitcount); + + alignas(ASTCENC_VECALIGN) float dec_weights_uquantf[BLOCK_MAX_WEIGHTS]; + + // Generate the optimized set of weights for the weight mode + compute_quantized_weights_for_decimation( + di, + weight_low_value[i], weight_high_value[i], + dec_weights_ideal + BLOCK_MAX_WEIGHTS * decimation_mode, + dec_weights_uquantf, + dec_weights_uquant + BLOCK_MAX_WEIGHTS * i, + bm.get_weight_quant_mode()); + + // Compute weight quantization errors for the block mode + qwt_errors[i] = compute_error_of_weight_set_1plane( + ei, + di, + dec_weights_uquantf); + } + + // Decide the optimal combination of color endpoint encodings and weight encodings + uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS]; + int block_mode_index[TUNE_MAX_TRIAL_CANDIDATES]; + + quant_method color_quant_level[TUNE_MAX_TRIAL_CANDIDATES]; + quant_method color_quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES]; + + unsigned int candidate_count = compute_ideal_endpoint_formats( + pi, blk, ei.ep, qwt_bitcounts, qwt_errors, + config.tune_candidate_limit, 0, max_block_modes, + partition_format_specifiers, block_mode_index, + color_quant_level, color_quant_level_mod, tmpbuf); + + // Iterate over the N believed-to-be-best modes to find out which one is actually best + float best_errorval_in_mode = ERROR_CALC_DEFAULT; + float best_errorval_in_scb = scb.errorval; + + for (unsigned int i = 0; i < candidate_count; i++) + { + TRACE_NODE(node0, "candidate"); + + const int bm_packed_index = block_mode_index[i]; + assert(bm_packed_index >= 0 && bm_packed_index < static_cast<int>(bsd.block_mode_count_1plane_selected)); + const block_mode& qw_bm = bsd.block_modes[bm_packed_index]; + + int decimation_mode = qw_bm.decimation_mode; + const auto& di = bsd.get_decimation_info(decimation_mode); + promise(di.weight_count > 0); + + trace_add_data("weight_x", di.weight_x); + trace_add_data("weight_y", di.weight_y); + trace_add_data("weight_z", di.weight_z); + trace_add_data("weight_quant", qw_bm.quant_mode); + + // Recompute the ideal color endpoints before storing them + vfloat4 rgbs_colors[BLOCK_MAX_PARTITIONS]; + vfloat4 rgbo_colors[BLOCK_MAX_PARTITIONS]; + + symbolic_compressed_block workscb; + endpoints workep = ei.ep; + + uint8_t* u8_weight_src = dec_weights_uquant + BLOCK_MAX_WEIGHTS * bm_packed_index; + + for (unsigned int j = 0; j < di.weight_count; j++) + { + workscb.weights[j] = u8_weight_src[j]; + } + + for (unsigned int l = 0; l < config.tune_refinement_limit; l++) + { + recompute_ideal_colors_1plane( + blk, pi, di, workscb.weights, + workep, rgbs_colors, rgbo_colors); + + // Quantize the chosen color, tracking if worth trying the mod value + bool all_same = color_quant_level[i] != color_quant_level_mod[i]; + for (unsigned int j = 0; j < partition_count; j++) + { + workscb.color_formats[j] = pack_color_endpoints( + workep.endpt0[j], + workep.endpt1[j], + rgbs_colors[j], + rgbo_colors[j], + partition_format_specifiers[i][j], + workscb.color_values[j], + color_quant_level[i]); + + all_same = all_same && workscb.color_formats[j] == workscb.color_formats[0]; + } + + // If all the color endpoint modes are the same, we get a few more bits to store colors; + // let's see if we can take advantage of this: requantize all the colors and see if the + // endpoint modes remain the same. + workscb.color_formats_matched = 0; + if (partition_count >= 2 && all_same) + { + uint8_t colorvals[BLOCK_MAX_PARTITIONS][12]; + uint8_t color_formats_mod[BLOCK_MAX_PARTITIONS] { 0 }; + bool all_same_mod = true; + for (unsigned int j = 0; j < partition_count; j++) + { + color_formats_mod[j] = pack_color_endpoints( + workep.endpt0[j], + workep.endpt1[j], + rgbs_colors[j], + rgbo_colors[j], + partition_format_specifiers[i][j], + colorvals[j], + color_quant_level_mod[i]); + + // Early out as soon as it's no longer possible to use mod + if (color_formats_mod[j] != color_formats_mod[0]) + { + all_same_mod = false; + break; + } + } + + if (all_same_mod) + { + workscb.color_formats_matched = 1; + for (unsigned int j = 0; j < BLOCK_MAX_PARTITIONS; j++) + { + for (unsigned int k = 0; k < 8; k++) + { + workscb.color_values[j][k] = colorvals[j][k]; + } + + workscb.color_formats[j] = color_formats_mod[j]; + } + } + } + + // Store header fields + workscb.partition_count = static_cast<uint8_t>(partition_count); + workscb.partition_index = static_cast<uint16_t>(partition_index); + workscb.plane2_component = -1; + workscb.quant_mode = workscb.color_formats_matched ? color_quant_level_mod[i] : color_quant_level[i]; + workscb.block_mode = qw_bm.mode_index; + workscb.block_type = SYM_BTYPE_NONCONST; + + // Pre-realign test + if (l == 0) + { + float errorval = compute_difference(config, bsd, workscb, blk); + if (errorval == -ERROR_CALC_DEFAULT) + { + errorval = -errorval; + workscb.block_type = SYM_BTYPE_ERROR; + } + + trace_add_data("error_prerealign", errorval); + best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode); + + // Average refinement improvement is 3.5% per iteration (allow 4.5%), but the first + // iteration can help more so we give it a extra 8% leeway. Use this knowledge to + // drive a heuristic to skip blocks that are unlikely to catch up with the best + // block we have already. + unsigned int iters_remaining = config.tune_refinement_limit - l; + float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.08f; + if (errorval > (threshold * best_errorval_in_scb)) + { + break; + } + + if (errorval < best_errorval_in_scb) + { + best_errorval_in_scb = errorval; + workscb.errorval = errorval; + scb = workscb; + + if (errorval < tune_errorval_threshold) + { + // Skip remaining candidates - this is "good enough" + i = candidate_count; + break; + } + } + } + + bool adjustments; + if (di.weight_count != bsd.texel_count) + { + adjustments = realign_weights_decimated( + config.profile, bsd, blk, workscb); + } + else + { + adjustments = realign_weights_undecimated( + config.profile, bsd, blk, workscb); + } + + // Post-realign test + float errorval = compute_difference(config, bsd, workscb, blk); + if (errorval == -ERROR_CALC_DEFAULT) + { + errorval = -errorval; + workscb.block_type = SYM_BTYPE_ERROR; + } + + trace_add_data("error_postrealign", errorval); + best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode); + + // Average refinement improvement is 3.5% per iteration, so skip blocks that are + // unlikely to catch up with the best block we have already. Assume a 4.5% per step to + // give benefit of the doubt ... + unsigned int iters_remaining = config.tune_refinement_limit - 1 - l; + float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.0f; + if (errorval > (threshold * best_errorval_in_scb)) + { + break; + } + + if (errorval < best_errorval_in_scb) + { + best_errorval_in_scb = errorval; + workscb.errorval = errorval; + scb = workscb; + + if (errorval < tune_errorval_threshold) + { + // Skip remaining candidates - this is "good enough" + i = candidate_count; + break; + } + } + + if (!adjustments) + { + break; + } + } + } + + return best_errorval_in_mode; +} + +/** + * @brief Compress a block using a chosen partitioning and 2 planes of weights. + * + * @param config The compressor configuration. + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param tune_errorval_threshold The error value threshold. + * @param plane2_component The component index for the second plane of weights. + * @param[out] scb The symbolic compressed block output. + * @param[out] tmpbuf The quantized weights for plane 1. + */ +static float compress_symbolic_block_for_partition_2planes( + const astcenc_config& config, + const block_size_descriptor& bsd, + const image_block& blk, + float tune_errorval_threshold, + unsigned int plane2_component, + symbolic_compressed_block& scb, + compression_working_buffers& tmpbuf, + int quant_limit +) { + promise(config.tune_candidate_limit > 0); + promise(config.tune_refinement_limit > 0); + promise(bsd.decimation_mode_count_selected > 0); + + int max_weight_quant = astc::min(static_cast<int>(QUANT_32), quant_limit); + + // Compute ideal weights and endpoint colors, with no quantization or decimation + endpoints_and_weights& ei1 = tmpbuf.ei1; + endpoints_and_weights& ei2 = tmpbuf.ei2; + + compute_ideal_colors_and_weights_2planes(bsd, blk, plane2_component, ei1, ei2); + + // Compute ideal weights and endpoint colors for every decimation + float* dec_weights_ideal = tmpbuf.dec_weights_ideal; + uint8_t* dec_weights_uquant = tmpbuf.dec_weights_uquant; + + // For each decimation mode, compute an ideal set of weights with no quantization + for (unsigned int i = 0; i < bsd.decimation_mode_count_selected; i++) + { + const auto& dm = bsd.get_decimation_mode(i); + if (!dm.is_ref_2_plane(static_cast<quant_method>(max_weight_quant))) + { + continue; + } + + const auto& di = bsd.get_decimation_info(i); + + compute_ideal_weights_for_decimation( + ei1, + di, + dec_weights_ideal + i * BLOCK_MAX_WEIGHTS); + + compute_ideal_weights_for_decimation( + ei2, + di, + dec_weights_ideal + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET); + } + + // Compute maximum colors for the endpoints and ideal weights, then for each endpoint and ideal + // weight pair, compute the smallest weight that will result in a color value greater than 1 + vfloat4 min_ep1(10.0f); + vfloat4 min_ep2(10.0f); + + vfloat4 ep1 = (vfloat4(1.0f) - ei1.ep.endpt0[0]) / (ei1.ep.endpt1[0] - ei1.ep.endpt0[0]); + vmask4 use_ep1 = (ep1 > vfloat4(0.5f)) & (ep1 < min_ep1); + min_ep1 = select(min_ep1, ep1, use_ep1); + + vfloat4 ep2 = (vfloat4(1.0f) - ei2.ep.endpt0[0]) / (ei2.ep.endpt1[0] - ei2.ep.endpt0[0]); + vmask4 use_ep2 = (ep2 > vfloat4(0.5f)) & (ep2 < min_ep2); + min_ep2 = select(min_ep2, ep2, use_ep2); + + vfloat4 err_max(ERROR_CALC_DEFAULT); + vmask4 err_mask = vint4::lane_id() == vint4(plane2_component); + + // Set the plane2 component to max error in ep1 + min_ep1 = select(min_ep1, err_max, err_mask); + + float min_wt_cutoff1 = hmin_s(min_ep1); + + // Set the minwt2 to the plane2 component min in ep2 + float min_wt_cutoff2 = hmin_s(select(err_max, min_ep2, err_mask)); + + compute_angular_endpoints_2planes( + bsd, dec_weights_ideal, max_weight_quant, tmpbuf); + + // For each mode (which specifies a decimation and a quantization): + // * Compute number of bits needed for the quantized weights + // * Generate an optimized set of quantized weights + // * Compute quantization errors for the mode + + float* weight_low_value1 = tmpbuf.weight_low_value1; + float* weight_high_value1 = tmpbuf.weight_high_value1; + float* weight_low_value2 = tmpbuf.weight_low_value2; + float* weight_high_value2 = tmpbuf.weight_high_value2; + + int8_t* qwt_bitcounts = tmpbuf.qwt_bitcounts; + float* qwt_errors = tmpbuf.qwt_errors; + + unsigned int start_2plane = bsd.block_mode_count_1plane_selected; + unsigned int end_2plane = bsd.block_mode_count_1plane_2plane_selected; + + for (unsigned int i = start_2plane; i < end_2plane; i++) + { + const block_mode& bm = bsd.block_modes[i]; + assert(bm.is_dual_plane); + + if (bm.quant_mode > max_weight_quant) + { + qwt_errors[i] = 1e38f; + continue; + } + + qwt_bitcounts[i] = static_cast<int8_t>(109 - bm.weight_bits); + + if (weight_high_value1[i] > 1.02f * min_wt_cutoff1) + { + weight_high_value1[i] = 1.0f; + } + + if (weight_high_value2[i] > 1.02f * min_wt_cutoff2) + { + weight_high_value2[i] = 1.0f; + } + + unsigned int decimation_mode = bm.decimation_mode; + const auto& di = bsd.get_decimation_info(decimation_mode); + + alignas(ASTCENC_VECALIGN) float dec_weights_uquantf[BLOCK_MAX_WEIGHTS]; + + // Generate the optimized set of weights for the mode + compute_quantized_weights_for_decimation( + di, + weight_low_value1[i], + weight_high_value1[i], + dec_weights_ideal + BLOCK_MAX_WEIGHTS * decimation_mode, + dec_weights_uquantf, + dec_weights_uquant + BLOCK_MAX_WEIGHTS * i, + bm.get_weight_quant_mode()); + + compute_quantized_weights_for_decimation( + di, + weight_low_value2[i], + weight_high_value2[i], + dec_weights_ideal + BLOCK_MAX_WEIGHTS * decimation_mode + WEIGHTS_PLANE2_OFFSET, + dec_weights_uquantf + WEIGHTS_PLANE2_OFFSET, + dec_weights_uquant + BLOCK_MAX_WEIGHTS * i + WEIGHTS_PLANE2_OFFSET, + bm.get_weight_quant_mode()); + + // Compute weight quantization errors for the block mode + qwt_errors[i] = compute_error_of_weight_set_2planes( + ei1, + ei2, + di, + dec_weights_uquantf, + dec_weights_uquantf + WEIGHTS_PLANE2_OFFSET); + } + + // Decide the optimal combination of color endpoint encodings and weight encodings + uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS]; + int block_mode_index[TUNE_MAX_TRIAL_CANDIDATES]; + + quant_method color_quant_level[TUNE_MAX_TRIAL_CANDIDATES]; + quant_method color_quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES]; + + endpoints epm; + merge_endpoints(ei1.ep, ei2.ep, plane2_component, epm); + + const auto& pi = bsd.get_partition_info(1, 0); + unsigned int candidate_count = compute_ideal_endpoint_formats( + pi, blk, epm, qwt_bitcounts, qwt_errors, + config.tune_candidate_limit, + bsd.block_mode_count_1plane_selected, bsd.block_mode_count_1plane_2plane_selected, + partition_format_specifiers, block_mode_index, + color_quant_level, color_quant_level_mod, tmpbuf); + + // Iterate over the N believed-to-be-best modes to find out which one is actually best + float best_errorval_in_mode = ERROR_CALC_DEFAULT; + float best_errorval_in_scb = scb.errorval; + + for (unsigned int i = 0; i < candidate_count; i++) + { + TRACE_NODE(node0, "candidate"); + + const int bm_packed_index = block_mode_index[i]; + assert(bm_packed_index >= static_cast<int>(bsd.block_mode_count_1plane_selected) && + bm_packed_index < static_cast<int>(bsd.block_mode_count_1plane_2plane_selected)); + const block_mode& qw_bm = bsd.block_modes[bm_packed_index]; + + int decimation_mode = qw_bm.decimation_mode; + const auto& di = bsd.get_decimation_info(decimation_mode); + promise(di.weight_count > 0); + + trace_add_data("weight_x", di.weight_x); + trace_add_data("weight_y", di.weight_y); + trace_add_data("weight_z", di.weight_z); + trace_add_data("weight_quant", qw_bm.quant_mode); + + vfloat4 rgbs_color; + vfloat4 rgbo_color; + + symbolic_compressed_block workscb; + endpoints workep = epm; + + uint8_t* u8_weight1_src = dec_weights_uquant + BLOCK_MAX_WEIGHTS * bm_packed_index; + uint8_t* u8_weight2_src = dec_weights_uquant + BLOCK_MAX_WEIGHTS * bm_packed_index + WEIGHTS_PLANE2_OFFSET; + + for (int j = 0; j < di.weight_count; j++) + { + workscb.weights[j] = u8_weight1_src[j]; + workscb.weights[j + WEIGHTS_PLANE2_OFFSET] = u8_weight2_src[j]; + } + + for (unsigned int l = 0; l < config.tune_refinement_limit; l++) + { + recompute_ideal_colors_2planes( + blk, bsd, di, + workscb.weights, workscb.weights + WEIGHTS_PLANE2_OFFSET, + workep, rgbs_color, rgbo_color, plane2_component); + + // Quantize the chosen color + workscb.color_formats[0] = pack_color_endpoints( + workep.endpt0[0], + workep.endpt1[0], + rgbs_color, rgbo_color, + partition_format_specifiers[i][0], + workscb.color_values[0], + color_quant_level[i]); + + // Store header fields + workscb.partition_count = 1; + workscb.partition_index = 0; + workscb.quant_mode = color_quant_level[i]; + workscb.color_formats_matched = 0; + workscb.block_mode = qw_bm.mode_index; + workscb.plane2_component = static_cast<int8_t>(plane2_component); + workscb.block_type = SYM_BTYPE_NONCONST; + + // Pre-realign test + if (l == 0) + { + float errorval = compute_symbolic_block_difference_2plane(config, bsd, workscb, blk); + if (errorval == -ERROR_CALC_DEFAULT) + { + errorval = -errorval; + workscb.block_type = SYM_BTYPE_ERROR; + } + + trace_add_data("error_prerealign", errorval); + best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode); + + // Average refinement improvement is 3.5% per iteration (allow 4.5%), but the first + // iteration can help more so we give it a extra 8% leeway. Use this knowledge to + // drive a heuristic to skip blocks that are unlikely to catch up with the best + // block we have already. + unsigned int iters_remaining = config.tune_refinement_limit - l; + float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.08f; + if (errorval > (threshold * best_errorval_in_scb)) + { + break; + } + + if (errorval < best_errorval_in_scb) + { + best_errorval_in_scb = errorval; + workscb.errorval = errorval; + scb = workscb; + + if (errorval < tune_errorval_threshold) + { + // Skip remaining candidates - this is "good enough" + i = candidate_count; + break; + } + } + } + + // Perform a final pass over the weights to try to improve them. + bool adjustments; + if (di.weight_count != bsd.texel_count) + { + adjustments = realign_weights_decimated( + config.profile, bsd, blk, workscb); + } + else + { + adjustments = realign_weights_undecimated( + config.profile, bsd, blk, workscb); + } + + // Post-realign test + float errorval = compute_symbolic_block_difference_2plane(config, bsd, workscb, blk); + if (errorval == -ERROR_CALC_DEFAULT) + { + errorval = -errorval; + workscb.block_type = SYM_BTYPE_ERROR; + } + + trace_add_data("error_postrealign", errorval); + best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode); + + // Average refinement improvement is 3.5% per iteration, so skip blocks that are + // unlikely to catch up with the best block we have already. Assume a 4.5% per step to + // give benefit of the doubt ... + unsigned int iters_remaining = config.tune_refinement_limit - 1 - l; + float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.0f; + if (errorval > (threshold * best_errorval_in_scb)) + { + break; + } + + if (errorval < best_errorval_in_scb) + { + best_errorval_in_scb = errorval; + workscb.errorval = errorval; + scb = workscb; + + if (errorval < tune_errorval_threshold) + { + // Skip remaining candidates - this is "good enough" + i = candidate_count; + break; + } + } + + if (!adjustments) + { + break; + } + } + } + + return best_errorval_in_mode; +} + +/** + * @brief Determine the lowest cross-channel correlation factor. + * + * @param texels_per_block The number of texels in a block. + * @param blk The image block color data to compress. + * + * @return Return the lowest correlation factor. + */ +static float prepare_block_statistics( + int texels_per_block, + const image_block& blk +) { + // Compute covariance matrix, as a collection of 10 scalars that form the upper-triangular row + // of the matrix. The matrix is symmetric, so this is all we need for this use case. + float rs = 0.0f; + float gs = 0.0f; + float bs = 0.0f; + float as = 0.0f; + float rr_var = 0.0f; + float gg_var = 0.0f; + float bb_var = 0.0f; + float aa_var = 0.0f; + float rg_cov = 0.0f; + float rb_cov = 0.0f; + float ra_cov = 0.0f; + float gb_cov = 0.0f; + float ga_cov = 0.0f; + float ba_cov = 0.0f; + + float weight_sum = 0.0f; + + promise(texels_per_block > 0); + for (int i = 0; i < texels_per_block; i++) + { + float weight = hadd_s(blk.channel_weight) / 4.0f; + assert(weight >= 0.0f); + weight_sum += weight; + + float r = blk.data_r[i]; + float g = blk.data_g[i]; + float b = blk.data_b[i]; + float a = blk.data_a[i]; + + float rw = r * weight; + rs += rw; + rr_var += r * rw; + rg_cov += g * rw; + rb_cov += b * rw; + ra_cov += a * rw; + + float gw = g * weight; + gs += gw; + gg_var += g * gw; + gb_cov += b * gw; + ga_cov += a * gw; + + float bw = b * weight; + bs += bw; + bb_var += b * bw; + ba_cov += a * bw; + + float aw = a * weight; + as += aw; + aa_var += a * aw; + } + + float rpt = 1.0f / astc::max(weight_sum, 1e-7f); + + rr_var -= rs * (rs * rpt); + rg_cov -= gs * (rs * rpt); + rb_cov -= bs * (rs * rpt); + ra_cov -= as * (rs * rpt); + + gg_var -= gs * (gs * rpt); + gb_cov -= bs * (gs * rpt); + ga_cov -= as * (gs * rpt); + + bb_var -= bs * (bs * rpt); + ba_cov -= as * (bs * rpt); + + aa_var -= as * (as * rpt); + + // These will give a NaN if a channel is constant - these are fixed up in the next step + rg_cov *= astc::rsqrt(rr_var * gg_var); + rb_cov *= astc::rsqrt(rr_var * bb_var); + ra_cov *= astc::rsqrt(rr_var * aa_var); + gb_cov *= astc::rsqrt(gg_var * bb_var); + ga_cov *= astc::rsqrt(gg_var * aa_var); + ba_cov *= astc::rsqrt(bb_var * aa_var); + + if (astc::isnan(rg_cov)) rg_cov = 1.0f; + if (astc::isnan(rb_cov)) rb_cov = 1.0f; + if (astc::isnan(ra_cov)) ra_cov = 1.0f; + if (astc::isnan(gb_cov)) gb_cov = 1.0f; + if (astc::isnan(ga_cov)) ga_cov = 1.0f; + if (astc::isnan(ba_cov)) ba_cov = 1.0f; + + float lowest_correlation = astc::min(fabsf(rg_cov), fabsf(rb_cov)); + lowest_correlation = astc::min(lowest_correlation, fabsf(ra_cov)); + lowest_correlation = astc::min(lowest_correlation, fabsf(gb_cov)); + lowest_correlation = astc::min(lowest_correlation, fabsf(ga_cov)); + lowest_correlation = astc::min(lowest_correlation, fabsf(ba_cov)); + + // Diagnostic trace points + trace_add_data("min_r", blk.data_min.lane<0>()); + trace_add_data("max_r", blk.data_max.lane<0>()); + trace_add_data("min_g", blk.data_min.lane<1>()); + trace_add_data("max_g", blk.data_max.lane<1>()); + trace_add_data("min_b", blk.data_min.lane<2>()); + trace_add_data("max_b", blk.data_max.lane<2>()); + trace_add_data("min_a", blk.data_min.lane<3>()); + trace_add_data("max_a", blk.data_max.lane<3>()); + trace_add_data("cov_rg", fabsf(rg_cov)); + trace_add_data("cov_rb", fabsf(rb_cov)); + trace_add_data("cov_ra", fabsf(ra_cov)); + trace_add_data("cov_gb", fabsf(gb_cov)); + trace_add_data("cov_ga", fabsf(ga_cov)); + trace_add_data("cov_ba", fabsf(ba_cov)); + + return lowest_correlation; +} + +/* See header for documentation. */ +void compress_block( + const astcenc_contexti& ctx, + const image_block& blk, + physical_compressed_block& pcb, + compression_working_buffers& tmpbuf) +{ + astcenc_profile decode_mode = ctx.config.profile; + symbolic_compressed_block scb; + const block_size_descriptor& bsd = *ctx.bsd; + float lowest_correl; + + TRACE_NODE(node0, "block"); + trace_add_data("pos_x", blk.xpos); + trace_add_data("pos_y", blk.ypos); + trace_add_data("pos_z", blk.zpos); + + // Set stricter block targets for luminance data as we have more bits to play with + bool block_is_l = blk.is_luminance(); + float block_is_l_scale = block_is_l ? 1.0f / 1.5f : 1.0f; + + // Set slightly stricter block targets for lumalpha data as we have more bits to play with + bool block_is_la = blk.is_luminancealpha(); + float block_is_la_scale = block_is_la ? 1.0f / 1.05f : 1.0f; + + bool block_skip_two_plane = false; + int max_partitions = ctx.config.tune_partition_count_limit; + + unsigned int requested_partition_indices[3] { + ctx.config.tune_2partition_index_limit, + ctx.config.tune_3partition_index_limit, + ctx.config.tune_4partition_index_limit + }; + + unsigned int requested_partition_trials[3] { + ctx.config.tune_2partitioning_candidate_limit, + ctx.config.tune_3partitioning_candidate_limit, + ctx.config.tune_4partitioning_candidate_limit + }; + +#if defined(ASTCENC_DIAGNOSTICS) + // Do this early in diagnostic builds so we can dump uniform metrics + // for every block. Do it later in release builds to avoid redundant work! + float error_weight_sum = hadd_s(blk.channel_weight) * bsd.texel_count; + float error_threshold = ctx.config.tune_db_limit + * error_weight_sum + * block_is_l_scale + * block_is_la_scale; + + lowest_correl = prepare_block_statistics(bsd.texel_count, blk); + trace_add_data("lowest_correl", lowest_correl); + trace_add_data("tune_error_threshold", error_threshold); +#endif + + // Detected a constant-color block + if (all(blk.data_min == blk.data_max)) + { + TRACE_NODE(node1, "pass"); + trace_add_data("partition_count", 0); + trace_add_data("plane_count", 1); + + scb.partition_count = 0; + + // Encode as FP16 if using HDR + if ((decode_mode == ASTCENC_PRF_HDR) || + (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A)) + { + scb.block_type = SYM_BTYPE_CONST_F16; + vint4 color_f16 = float_to_float16(blk.origin_texel); + store(color_f16, scb.constant_color); + } + // Encode as UNORM16 if NOT using HDR + else + { + scb.block_type = SYM_BTYPE_CONST_U16; + vfloat4 color_f32 = clamp(0.0f, 1.0f, blk.origin_texel) * 65535.0f; + vint4 color_u16 = float_to_int_rtn(color_f32); + store(color_u16, scb.constant_color); + } + + trace_add_data("exit", "quality hit"); + + symbolic_to_physical(bsd, scb, pcb); + return; + } + +#if !defined(ASTCENC_DIAGNOSTICS) + float error_weight_sum = hadd_s(blk.channel_weight) * bsd.texel_count; + float error_threshold = ctx.config.tune_db_limit + * error_weight_sum + * block_is_l_scale + * block_is_la_scale; +#endif + + // Set SCB and mode errors to a very high error value + scb.errorval = ERROR_CALC_DEFAULT; + scb.block_type = SYM_BTYPE_ERROR; + + float best_errorvals_for_pcount[BLOCK_MAX_PARTITIONS] { + ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT + }; + + float exit_thresholds_for_pcount[BLOCK_MAX_PARTITIONS] { + 0.0f, + ctx.config.tune_2_partition_early_out_limit_factor, + ctx.config.tune_3_partition_early_out_limit_factor, + 0.0f + }; + + // Trial using 1 plane of weights and 1 partition. + + // Most of the time we test it twice, first with a mode cutoff of 0 and then with the specified + // mode cutoff. This causes an early-out that speeds up encoding of easy blocks. However, this + // optimization is disabled for 4x4 and 5x4 blocks where it nearly always slows down the + // compression and slightly reduces image quality. + + float errorval_mult[2] { + 1.0f / ctx.config.tune_mse_overshoot, + 1.0f + }; + + static const float errorval_overshoot = 1.0f / ctx.config.tune_mse_overshoot; + + // Only enable MODE0 fast path (trial 0) if 2D, and more than 25 texels + int start_trial = 1; + if ((bsd.texel_count >= TUNE_MIN_TEXELS_MODE0_FASTPATH) && (bsd.zdim == 1)) + { + start_trial = 0; + } + + int quant_limit = QUANT_32; + for (int i = start_trial; i < 2; i++) + { + TRACE_NODE(node1, "pass"); + trace_add_data("partition_count", 1); + trace_add_data("plane_count", 1); + trace_add_data("search_mode", i); + + float errorval = compress_symbolic_block_for_partition_1plane( + ctx.config, bsd, blk, i == 0, + error_threshold * errorval_mult[i] * errorval_overshoot, + 1, 0, scb, tmpbuf, QUANT_32); + + // Record the quant level so we can use the filter later searches + const auto& bm = bsd.get_block_mode(scb.block_mode); + quant_limit = bm.get_weight_quant_mode(); + + best_errorvals_for_pcount[0] = astc::min(best_errorvals_for_pcount[0], errorval); + if (errorval < (error_threshold * errorval_mult[i])) + { + trace_add_data("exit", "quality hit"); + goto END_OF_TESTS; + } + } + +#if !defined(ASTCENC_DIAGNOSTICS) + lowest_correl = prepare_block_statistics(bsd.texel_count, blk); +#endif + + block_skip_two_plane = lowest_correl > ctx.config.tune_2_plane_early_out_limit_correlation; + + // Test the four possible 1-partition, 2-planes modes. Do this in reverse, as + // alpha is the most likely to be non-correlated if it is present in the data. + for (int i = BLOCK_MAX_COMPONENTS - 1; i >= 0; i--) + { + TRACE_NODE(node1, "pass"); + trace_add_data("partition_count", 1); + trace_add_data("plane_count", 2); + trace_add_data("plane_component", i); + + if (block_skip_two_plane) + { + trace_add_data("skip", "tune_2_plane_early_out_limit_correlation"); + continue; + } + + if (blk.grayscale && i != 3) + { + trace_add_data("skip", "grayscale block"); + continue; + } + + if (blk.is_constant_channel(i)) + { + trace_add_data("skip", "constant component"); + continue; + } + + float errorval = compress_symbolic_block_for_partition_2planes( + ctx.config, bsd, blk, error_threshold * errorval_overshoot, + i, scb, tmpbuf, quant_limit); + + // If attempting two planes is much worse than the best one plane result + // then further two plane searches are unlikely to help so move on ... + if (errorval > (best_errorvals_for_pcount[0] * 1.85f)) + { + break; + } + + if (errorval < error_threshold) + { + trace_add_data("exit", "quality hit"); + goto END_OF_TESTS; + } + } + + // Find best blocks for 2, 3 and 4 partitions + for (int partition_count = 2; partition_count <= max_partitions; partition_count++) + { + unsigned int partition_indices[TUNE_MAX_PARTITIONING_CANDIDATES]; + + unsigned int requested_indices = requested_partition_indices[partition_count - 2]; + + unsigned int requested_trials = requested_partition_trials[partition_count - 2]; + requested_trials = astc::min(requested_trials, requested_indices); + + unsigned int actual_trials = find_best_partition_candidates( + bsd, blk, partition_count, requested_indices, partition_indices, requested_trials); + + float best_error_in_prev = best_errorvals_for_pcount[partition_count - 2]; + + for (unsigned int i = 0; i < actual_trials; i++) + { + TRACE_NODE(node1, "pass"); + trace_add_data("partition_count", partition_count); + trace_add_data("partition_index", partition_indices[i]); + trace_add_data("plane_count", 1); + trace_add_data("search_mode", i); + + float errorval = compress_symbolic_block_for_partition_1plane( + ctx.config, bsd, blk, false, + error_threshold * errorval_overshoot, + partition_count, partition_indices[i], + scb, tmpbuf, quant_limit); + + best_errorvals_for_pcount[partition_count - 1] = astc::min(best_errorvals_for_pcount[partition_count - 1], errorval); + + // If using N partitions doesn't improve much over using N-1 partitions then skip trying + // N+1. Error can dramatically improve if the data is correlated or non-correlated and + // aligns with a partitioning that suits that encoding, so for this inner loop check add + // a large error scale because the "other" trial could be a lot better. + float best_error = best_errorvals_for_pcount[partition_count - 1]; + float best_error_scale = exit_thresholds_for_pcount[partition_count - 1] * 1.85f; + if (best_error > (best_error_in_prev * best_error_scale)) + { + trace_add_data("skip", "tune_partition_early_out_limit_factor"); + goto END_OF_TESTS; + } + + if (errorval < error_threshold) + { + trace_add_data("exit", "quality hit"); + goto END_OF_TESTS; + } + } + + // If using N partitions doesn't improve much over using N-1 partitions then skip trying N+1 + float best_error = best_errorvals_for_pcount[partition_count - 1]; + float best_error_scale = exit_thresholds_for_pcount[partition_count - 1]; + if (best_error > (best_error_in_prev * best_error_scale)) + { + trace_add_data("skip", "tune_partition_early_out_limit_factor"); + goto END_OF_TESTS; + } + } + + trace_add_data("exit", "quality not hit"); + +END_OF_TESTS: + // If we still have an error block then convert to something we can encode + // TODO: Do something more sensible here, such as average color block + if (scb.block_type == SYM_BTYPE_ERROR) + { +#if defined(ASTCENC_DIAGNOSTICS) + static bool printed_once = false; + if (!printed_once) + { + printed_once = true; + printf("WARN: At least one block failed to find a valid encoding.\n" + " Try increasing compression quality settings.\n\n"); + } +#endif + + scb.block_type = SYM_BTYPE_CONST_U16; + vfloat4 color_f32 = clamp(0.0f, 1.0f, blk.origin_texel) * 65535.0f; + vint4 color_u16 = float_to_int_rtn(color_f32); + store(color_u16, scb.constant_color); + } + + // Compress to a physical block + symbolic_to_physical(bsd, scb, pcb); +} + +#endif diff --git a/thirdparty/astcenc/astcenc_compute_variance.cpp b/thirdparty/astcenc/astcenc_compute_variance.cpp new file mode 100644 index 0000000000..48a4af8cef --- /dev/null +++ b/thirdparty/astcenc/astcenc_compute_variance.cpp @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions to calculate variance per component in a NxN footprint. + * + * We need N to be parametric, so the routine below uses summed area tables in order to execute in + * O(1) time independent of how big N is. + * + * The addition uses a Brent-Kung-based parallel prefix adder. This uses the prefix tree to first + * perform a binary reduction, and then distributes the results. This method means that there is no + * serial dependency between a given element and the next one, and also significantly improves + * numerical stability allowing us to use floats rather than doubles. + */ + +#include "astcenc_internal.h" + +#include <cassert> + +/** + * @brief Generate a prefix-sum array using the Brent-Kung algorithm. + * + * This will take an input array of the form: + * v0, v1, v2, ... + * ... and modify in-place to turn it into a prefix-sum array of the form: + * v0, v0+v1, v0+v1+v2, ... + * + * @param d The array to prefix-sum. + * @param items The number of items in the array. + * @param stride The item spacing in the array; i.e. dense arrays should use 1. + */ +static void brent_kung_prefix_sum( + vfloat4* d, + size_t items, + int stride +) { + if (items < 2) + return; + + size_t lc_stride = 2; + size_t log2_stride = 1; + + // The reduction-tree loop + do { + size_t step = lc_stride >> 1; + size_t start = lc_stride - 1; + size_t iters = items >> log2_stride; + + vfloat4 *da = d + (start * stride); + ptrdiff_t ofs = -static_cast<ptrdiff_t>(step * stride); + size_t ofs_stride = stride << log2_stride; + + while (iters) + { + *da = *da + da[ofs]; + da += ofs_stride; + iters--; + } + + log2_stride += 1; + lc_stride <<= 1; + } while (lc_stride <= items); + + // The expansion-tree loop + do { + log2_stride -= 1; + lc_stride >>= 1; + + size_t step = lc_stride >> 1; + size_t start = step + lc_stride - 1; + size_t iters = (items - step) >> log2_stride; + + vfloat4 *da = d + (start * stride); + ptrdiff_t ofs = -static_cast<ptrdiff_t>(step * stride); + size_t ofs_stride = stride << log2_stride; + + while (iters) + { + *da = *da + da[ofs]; + da += ofs_stride; + iters--; + } + } while (lc_stride > 2); +} + +/* See header for documentation. */ +void compute_pixel_region_variance( + astcenc_contexti& ctx, + const pixel_region_args& arg +) { + // Unpack the memory structure into local variables + const astcenc_image* img = arg.img; + astcenc_swizzle swz = arg.swz; + bool have_z = arg.have_z; + + int size_x = arg.size_x; + int size_y = arg.size_y; + int size_z = arg.size_z; + + int offset_x = arg.offset_x; + int offset_y = arg.offset_y; + int offset_z = arg.offset_z; + + int alpha_kernel_radius = arg.alpha_kernel_radius; + + float* input_alpha_averages = ctx.input_alpha_averages; + vfloat4* work_memory = arg.work_memory; + + // Compute memory sizes and dimensions that we need + int kernel_radius = alpha_kernel_radius; + int kerneldim = 2 * kernel_radius + 1; + int kernel_radius_xy = kernel_radius; + int kernel_radius_z = have_z ? kernel_radius : 0; + + int padsize_x = size_x + kerneldim; + int padsize_y = size_y + kerneldim; + int padsize_z = size_z + (have_z ? kerneldim : 0); + int sizeprod = padsize_x * padsize_y * padsize_z; + + int zd_start = have_z ? 1 : 0; + + vfloat4 *varbuf1 = work_memory; + vfloat4 *varbuf2 = work_memory + sizeprod; + + // Scaling factors to apply to Y and Z for accesses into the work buffers + int yst = padsize_x; + int zst = padsize_x * padsize_y; + + // Scaling factors to apply to Y and Z for accesses into result buffers + int ydt = img->dim_x; + int zdt = img->dim_x * img->dim_y; + + // Macros to act as accessor functions for the work-memory + #define VARBUF1(z, y, x) varbuf1[z * zst + y * yst + x] + #define VARBUF2(z, y, x) varbuf2[z * zst + y * yst + x] + + // Load N and N^2 values into the work buffers + if (img->data_type == ASTCENC_TYPE_U8) + { + // Swizzle data structure 4 = ZERO, 5 = ONE + uint8_t data[6]; + data[ASTCENC_SWZ_0] = 0; + data[ASTCENC_SWZ_1] = 255; + + for (int z = zd_start; z < padsize_z; z++) + { + int z_src = (z - zd_start) + offset_z - kernel_radius_z; + z_src = astc::clamp(z_src, 0, static_cast<int>(img->dim_z - 1)); + uint8_t* data8 = static_cast<uint8_t*>(img->data[z_src]); + + for (int y = 1; y < padsize_y; y++) + { + int y_src = (y - 1) + offset_y - kernel_radius_xy; + y_src = astc::clamp(y_src, 0, static_cast<int>(img->dim_y - 1)); + + for (int x = 1; x < padsize_x; x++) + { + int x_src = (x - 1) + offset_x - kernel_radius_xy; + x_src = astc::clamp(x_src, 0, static_cast<int>(img->dim_x - 1)); + + data[0] = data8[(4 * img->dim_x * y_src) + (4 * x_src )]; + data[1] = data8[(4 * img->dim_x * y_src) + (4 * x_src + 1)]; + data[2] = data8[(4 * img->dim_x * y_src) + (4 * x_src + 2)]; + data[3] = data8[(4 * img->dim_x * y_src) + (4 * x_src + 3)]; + + uint8_t r = data[swz.r]; + uint8_t g = data[swz.g]; + uint8_t b = data[swz.b]; + uint8_t a = data[swz.a]; + + vfloat4 d = vfloat4 (r * (1.0f / 255.0f), + g * (1.0f / 255.0f), + b * (1.0f / 255.0f), + a * (1.0f / 255.0f)); + + VARBUF1(z, y, x) = d; + VARBUF2(z, y, x) = d * d; + } + } + } + } + else if (img->data_type == ASTCENC_TYPE_F16) + { + // Swizzle data structure 4 = ZERO, 5 = ONE (in FP16) + uint16_t data[6]; + data[ASTCENC_SWZ_0] = 0; + data[ASTCENC_SWZ_1] = 0x3C00; + + for (int z = zd_start; z < padsize_z; z++) + { + int z_src = (z - zd_start) + offset_z - kernel_radius_z; + z_src = astc::clamp(z_src, 0, static_cast<int>(img->dim_z - 1)); + uint16_t* data16 = static_cast<uint16_t*>(img->data[z_src]); + + for (int y = 1; y < padsize_y; y++) + { + int y_src = (y - 1) + offset_y - kernel_radius_xy; + y_src = astc::clamp(y_src, 0, static_cast<int>(img->dim_y - 1)); + + for (int x = 1; x < padsize_x; x++) + { + int x_src = (x - 1) + offset_x - kernel_radius_xy; + x_src = astc::clamp(x_src, 0, static_cast<int>(img->dim_x - 1)); + + data[0] = data16[(4 * img->dim_x * y_src) + (4 * x_src )]; + data[1] = data16[(4 * img->dim_x * y_src) + (4 * x_src + 1)]; + data[2] = data16[(4 * img->dim_x * y_src) + (4 * x_src + 2)]; + data[3] = data16[(4 * img->dim_x * y_src) + (4 * x_src + 3)]; + + vint4 di(data[swz.r], data[swz.g], data[swz.b], data[swz.a]); + vfloat4 d = float16_to_float(di); + + VARBUF1(z, y, x) = d; + VARBUF2(z, y, x) = d * d; + } + } + } + } + else // if (img->data_type == ASTCENC_TYPE_F32) + { + assert(img->data_type == ASTCENC_TYPE_F32); + + // Swizzle data structure 4 = ZERO, 5 = ONE (in FP16) + float data[6]; + data[ASTCENC_SWZ_0] = 0.0f; + data[ASTCENC_SWZ_1] = 1.0f; + + for (int z = zd_start; z < padsize_z; z++) + { + int z_src = (z - zd_start) + offset_z - kernel_radius_z; + z_src = astc::clamp(z_src, 0, static_cast<int>(img->dim_z - 1)); + float* data32 = static_cast<float*>(img->data[z_src]); + + for (int y = 1; y < padsize_y; y++) + { + int y_src = (y - 1) + offset_y - kernel_radius_xy; + y_src = astc::clamp(y_src, 0, static_cast<int>(img->dim_y - 1)); + + for (int x = 1; x < padsize_x; x++) + { + int x_src = (x - 1) + offset_x - kernel_radius_xy; + x_src = astc::clamp(x_src, 0, static_cast<int>(img->dim_x - 1)); + + data[0] = data32[(4 * img->dim_x * y_src) + (4 * x_src )]; + data[1] = data32[(4 * img->dim_x * y_src) + (4 * x_src + 1)]; + data[2] = data32[(4 * img->dim_x * y_src) + (4 * x_src + 2)]; + data[3] = data32[(4 * img->dim_x * y_src) + (4 * x_src + 3)]; + + float r = data[swz.r]; + float g = data[swz.g]; + float b = data[swz.b]; + float a = data[swz.a]; + + vfloat4 d(r, g, b, a); + + VARBUF1(z, y, x) = d; + VARBUF2(z, y, x) = d * d; + } + } + } + } + + // Pad with an extra layer of 0s; this forms the edge of the SAT tables + vfloat4 vbz = vfloat4::zero(); + for (int z = 0; z < padsize_z; z++) + { + for (int y = 0; y < padsize_y; y++) + { + VARBUF1(z, y, 0) = vbz; + VARBUF2(z, y, 0) = vbz; + } + + for (int x = 0; x < padsize_x; x++) + { + VARBUF1(z, 0, x) = vbz; + VARBUF2(z, 0, x) = vbz; + } + } + + if (have_z) + { + for (int y = 0; y < padsize_y; y++) + { + for (int x = 0; x < padsize_x; x++) + { + VARBUF1(0, y, x) = vbz; + VARBUF2(0, y, x) = vbz; + } + } + } + + // Generate summed-area tables for N and N^2; this is done in-place, using + // a Brent-Kung parallel-prefix based algorithm to minimize precision loss + for (int z = zd_start; z < padsize_z; z++) + { + for (int y = 1; y < padsize_y; y++) + { + brent_kung_prefix_sum(&(VARBUF1(z, y, 1)), padsize_x - 1, 1); + brent_kung_prefix_sum(&(VARBUF2(z, y, 1)), padsize_x - 1, 1); + } + } + + for (int z = zd_start; z < padsize_z; z++) + { + for (int x = 1; x < padsize_x; x++) + { + brent_kung_prefix_sum(&(VARBUF1(z, 1, x)), padsize_y - 1, yst); + brent_kung_prefix_sum(&(VARBUF2(z, 1, x)), padsize_y - 1, yst); + } + } + + if (have_z) + { + for (int y = 1; y < padsize_y; y++) + { + for (int x = 1; x < padsize_x; x++) + { + brent_kung_prefix_sum(&(VARBUF1(1, y, x)), padsize_z - 1, zst); + brent_kung_prefix_sum(&(VARBUF2(1, y, x)), padsize_z - 1, zst); + } + } + } + + // Compute a few constants used in the variance-calculation. + float alpha_kdim = static_cast<float>(2 * alpha_kernel_radius + 1); + float alpha_rsamples; + + if (have_z) + { + alpha_rsamples = 1.0f / (alpha_kdim * alpha_kdim * alpha_kdim); + } + else + { + alpha_rsamples = 1.0f / (alpha_kdim * alpha_kdim); + } + + // Use the summed-area tables to compute variance for each neighborhood + if (have_z) + { + for (int z = 0; z < size_z; z++) + { + int z_src = z + kernel_radius_z; + int z_dst = z + offset_z; + int z_low = z_src - alpha_kernel_radius; + int z_high = z_src + alpha_kernel_radius + 1; + + for (int y = 0; y < size_y; y++) + { + int y_src = y + kernel_radius_xy; + int y_dst = y + offset_y; + int y_low = y_src - alpha_kernel_radius; + int y_high = y_src + alpha_kernel_radius + 1; + + for (int x = 0; x < size_x; x++) + { + int x_src = x + kernel_radius_xy; + int x_dst = x + offset_x; + int x_low = x_src - alpha_kernel_radius; + int x_high = x_src + alpha_kernel_radius + 1; + + // Summed-area table lookups for alpha average + float vasum = ( VARBUF1(z_high, y_low, x_low).lane<3>() + - VARBUF1(z_high, y_low, x_high).lane<3>() + - VARBUF1(z_high, y_high, x_low).lane<3>() + + VARBUF1(z_high, y_high, x_high).lane<3>()) - + ( VARBUF1(z_low, y_low, x_low).lane<3>() + - VARBUF1(z_low, y_low, x_high).lane<3>() + - VARBUF1(z_low, y_high, x_low).lane<3>() + + VARBUF1(z_low, y_high, x_high).lane<3>()); + + int out_index = z_dst * zdt + y_dst * ydt + x_dst; + input_alpha_averages[out_index] = (vasum * alpha_rsamples); + } + } + } + } + else + { + for (int y = 0; y < size_y; y++) + { + int y_src = y + kernel_radius_xy; + int y_dst = y + offset_y; + int y_low = y_src - alpha_kernel_radius; + int y_high = y_src + alpha_kernel_radius + 1; + + for (int x = 0; x < size_x; x++) + { + int x_src = x + kernel_radius_xy; + int x_dst = x + offset_x; + int x_low = x_src - alpha_kernel_radius; + int x_high = x_src + alpha_kernel_radius + 1; + + // Summed-area table lookups for alpha average + float vasum = VARBUF1(0, y_low, x_low).lane<3>() + - VARBUF1(0, y_low, x_high).lane<3>() + - VARBUF1(0, y_high, x_low).lane<3>() + + VARBUF1(0, y_high, x_high).lane<3>(); + + int out_index = y_dst * ydt + x_dst; + input_alpha_averages[out_index] = (vasum * alpha_rsamples); + } + } + } +} + +/* See header for documentation. */ +unsigned int init_compute_averages( + const astcenc_image& img, + unsigned int alpha_kernel_radius, + const astcenc_swizzle& swz, + avg_args& ag +) { + unsigned int size_x = img.dim_x; + unsigned int size_y = img.dim_y; + unsigned int size_z = img.dim_z; + + // Compute maximum block size and from that the working memory buffer size + unsigned int kernel_radius = alpha_kernel_radius; + unsigned int kerneldim = 2 * kernel_radius + 1; + + bool have_z = (size_z > 1); + unsigned int max_blk_size_xy = have_z ? 16 : 32; + unsigned int max_blk_size_z = astc::min(size_z, have_z ? 16u : 1u); + + unsigned int max_padsize_xy = max_blk_size_xy + kerneldim; + unsigned int max_padsize_z = max_blk_size_z + (have_z ? kerneldim : 0); + + // Perform block-wise averages calculations across the image + // Initialize fields which are not populated until later + ag.arg.size_x = 0; + ag.arg.size_y = 0; + ag.arg.size_z = 0; + ag.arg.offset_x = 0; + ag.arg.offset_y = 0; + ag.arg.offset_z = 0; + ag.arg.work_memory = nullptr; + + ag.arg.img = &img; + ag.arg.swz = swz; + ag.arg.have_z = have_z; + ag.arg.alpha_kernel_radius = alpha_kernel_radius; + + ag.img_size_x = size_x; + ag.img_size_y = size_y; + ag.img_size_z = size_z; + ag.blk_size_xy = max_blk_size_xy; + ag.blk_size_z = max_blk_size_z; + ag.work_memory_size = 2 * max_padsize_xy * max_padsize_xy * max_padsize_z; + + // The parallel task count + unsigned int z_tasks = (size_z + max_blk_size_z - 1) / max_blk_size_z; + unsigned int y_tasks = (size_y + max_blk_size_xy - 1) / max_blk_size_xy; + return z_tasks * y_tasks; +} + +#endif diff --git a/thirdparty/astcenc/astcenc_decompress_symbolic.cpp b/thirdparty/astcenc/astcenc_decompress_symbolic.cpp new file mode 100644 index 0000000000..39e5525c3b --- /dev/null +++ b/thirdparty/astcenc/astcenc_decompress_symbolic.cpp @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions to decompress a symbolic block. + */ + +#include "astcenc_internal.h" + +#include <stdio.h> +#include <assert.h> + +/** + * @brief Compute the integer linear interpolation of two color endpoints. + * + * @param decode_mode The ASTC profile (linear or sRGB) + * @param color0 The endpoint0 color. + * @param color1 The endpoint1 color. + * @param weights The interpolation weight (between 0 and 64). + * + * @return The interpolated color. + */ +static vint4 lerp_color_int( + astcenc_profile decode_mode, + vint4 color0, + vint4 color1, + vint4 weights +) { + vint4 weight1 = weights; + vint4 weight0 = vint4(64) - weight1; + + if (decode_mode == ASTCENC_PRF_LDR_SRGB) + { + color0 = asr<8>(color0); + color1 = asr<8>(color1); + } + + vint4 color = (color0 * weight0) + (color1 * weight1) + vint4(32); + color = asr<6>(color); + + if (decode_mode == ASTCENC_PRF_LDR_SRGB) + { + color = color * vint4(257); + } + + return color; +} + + +/** + * @brief Convert integer color value into a float value for the decoder. + * + * @param data The integer color value post-interpolation. + * @param lns_mask If set treat lane as HDR (LNS) else LDR (unorm16). + * + * @return The float color value. + */ +static inline vfloat4 decode_texel( + vint4 data, + vmask4 lns_mask +) { + vint4 color_lns = vint4::zero(); + vint4 color_unorm = vint4::zero(); + + if (any(lns_mask)) + { + color_lns = lns_to_sf16(data); + } + + if (!all(lns_mask)) + { + color_unorm = unorm16_to_sf16(data); + } + + // Pick components and then convert to FP16 + vint4 datai = select(color_unorm, color_lns, lns_mask); + return float16_to_float(datai); +} + +/* See header for documentation. */ +void unpack_weights( + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const decimation_info& di, + bool is_dual_plane, + int weights_plane1[BLOCK_MAX_TEXELS], + int weights_plane2[BLOCK_MAX_TEXELS] +) { + // Safe to overshoot as all arrays are allocated to full size + if (!is_dual_plane) + { + // Build full 64-entry weight lookup table + vint4 tab0(reinterpret_cast<const int*>(scb.weights + 0)); + vint4 tab1(reinterpret_cast<const int*>(scb.weights + 16)); + vint4 tab2(reinterpret_cast<const int*>(scb.weights + 32)); + vint4 tab3(reinterpret_cast<const int*>(scb.weights + 48)); + + vint tab0p, tab1p, tab2p, tab3p; + vtable_prepare(tab0, tab1, tab2, tab3, tab0p, tab1p, tab2p, tab3p); + + for (unsigned int i = 0; i < bsd.texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint summed_value(8); + vint weight_count(di.texel_weight_count + i); + int max_weight_count = hmax(weight_count).lane<0>(); + + promise(max_weight_count > 0); + for (int j = 0; j < max_weight_count; j++) + { + vint texel_weights(di.texel_weights_tr[j] + i); + vint texel_weights_int(di.texel_weight_contribs_int_tr[j] + i); + + summed_value += vtable_8bt_32bi(tab0p, tab1p, tab2p, tab3p, texel_weights) * texel_weights_int; + } + + store(lsr<4>(summed_value), weights_plane1 + i); + } + } + else + { + // Build a 32-entry weight lookup table per plane + // Plane 1 + vint4 tab0_plane1(reinterpret_cast<const int*>(scb.weights + 0)); + vint4 tab1_plane1(reinterpret_cast<const int*>(scb.weights + 16)); + vint tab0_plane1p, tab1_plane1p; + vtable_prepare(tab0_plane1, tab1_plane1, tab0_plane1p, tab1_plane1p); + + // Plane 2 + vint4 tab0_plane2(reinterpret_cast<const int*>(scb.weights + 32)); + vint4 tab1_plane2(reinterpret_cast<const int*>(scb.weights + 48)); + vint tab0_plane2p, tab1_plane2p; + vtable_prepare(tab0_plane2, tab1_plane2, tab0_plane2p, tab1_plane2p); + + for (unsigned int i = 0; i < bsd.texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint sum_plane1(8); + vint sum_plane2(8); + + vint weight_count(di.texel_weight_count + i); + int max_weight_count = hmax(weight_count).lane<0>(); + + promise(max_weight_count > 0); + for (int j = 0; j < max_weight_count; j++) + { + vint texel_weights(di.texel_weights_tr[j] + i); + vint texel_weights_int(di.texel_weight_contribs_int_tr[j] + i); + + sum_plane1 += vtable_8bt_32bi(tab0_plane1p, tab1_plane1p, texel_weights) * texel_weights_int; + sum_plane2 += vtable_8bt_32bi(tab0_plane2p, tab1_plane2p, texel_weights) * texel_weights_int; + } + + store(lsr<4>(sum_plane1), weights_plane1 + i); + store(lsr<4>(sum_plane2), weights_plane2 + i); + } + } +} + +/** + * @brief Return an FP32 NaN value for use in error colors. + * + * This NaN encoding will turn into 0xFFFF when converted to an FP16 NaN. + * + * @return The float color value. + */ +static float error_color_nan() +{ + if32 v; + v.u = 0xFFFFE000U; + return v.f; +} + +/* See header for documentation. */ +void decompress_symbolic_block( + astcenc_profile decode_mode, + const block_size_descriptor& bsd, + int xpos, + int ypos, + int zpos, + const symbolic_compressed_block& scb, + image_block& blk +) { + blk.xpos = xpos; + blk.ypos = ypos; + blk.zpos = zpos; + + blk.data_min = vfloat4::zero(); + blk.data_mean = vfloat4::zero(); + blk.data_max = vfloat4::zero(); + blk.grayscale = false; + + // If we detected an error-block, blow up immediately. + if (scb.block_type == SYM_BTYPE_ERROR) + { + for (unsigned int i = 0; i < bsd.texel_count; i++) + { + blk.data_r[i] = error_color_nan(); + blk.data_g[i] = error_color_nan(); + blk.data_b[i] = error_color_nan(); + blk.data_a[i] = error_color_nan(); + blk.rgb_lns[i] = 0; + blk.alpha_lns[i] = 0; + } + + return; + } + + if ((scb.block_type == SYM_BTYPE_CONST_F16) || + (scb.block_type == SYM_BTYPE_CONST_U16)) + { + vfloat4 color; + uint8_t use_lns = 0; + + // UNORM16 constant color block + if (scb.block_type == SYM_BTYPE_CONST_U16) + { + vint4 colori(scb.constant_color); + + // For sRGB decoding a real decoder would just use the top 8 bits for color conversion. + // We don't color convert, so rescale the top 8 bits into the full 16 bit dynamic range. + if (decode_mode == ASTCENC_PRF_LDR_SRGB) + { + colori = asr<8>(colori) * 257; + } + + vint4 colorf16 = unorm16_to_sf16(colori); + color = float16_to_float(colorf16); + } + // FLOAT16 constant color block + else + { + switch (decode_mode) + { + case ASTCENC_PRF_LDR_SRGB: + case ASTCENC_PRF_LDR: + color = vfloat4(error_color_nan()); + break; + case ASTCENC_PRF_HDR_RGB_LDR_A: + case ASTCENC_PRF_HDR: + // Constant-color block; unpack from FP16 to FP32. + color = float16_to_float(vint4(scb.constant_color)); + use_lns = 1; + break; + } + } + + for (unsigned int i = 0; i < bsd.texel_count; i++) + { + blk.data_r[i] = color.lane<0>(); + blk.data_g[i] = color.lane<1>(); + blk.data_b[i] = color.lane<2>(); + blk.data_a[i] = color.lane<3>(); + blk.rgb_lns[i] = use_lns; + blk.alpha_lns[i] = use_lns; + } + + return; + } + + // Get the appropriate partition-table entry + int partition_count = scb.partition_count; + const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index); + + // Get the appropriate block descriptors + const auto& bm = bsd.get_block_mode(scb.block_mode); + const auto& di = bsd.get_decimation_info(bm.decimation_mode); + + bool is_dual_plane = static_cast<bool>(bm.is_dual_plane); + + // Unquantize and undecimate the weights + int plane1_weights[BLOCK_MAX_TEXELS]; + int plane2_weights[BLOCK_MAX_TEXELS]; + unpack_weights(bsd, scb, di, is_dual_plane, plane1_weights, plane2_weights); + + // Now that we have endpoint colors and weights, we can unpack texel colors + int plane2_component = scb.plane2_component; + vmask4 plane2_mask = vint4::lane_id() == vint4(plane2_component); + + for (int i = 0; i < partition_count; i++) + { + // Decode the color endpoints for this partition + vint4 ep0; + vint4 ep1; + bool rgb_lns; + bool a_lns; + + unpack_color_endpoints(decode_mode, + scb.color_formats[i], + scb.color_values[i], + rgb_lns, a_lns, + ep0, ep1); + + vmask4 lns_mask(rgb_lns, rgb_lns, rgb_lns, a_lns); + + int texel_count = pi.partition_texel_count[i]; + for (int j = 0; j < texel_count; j++) + { + int tix = pi.texels_of_partition[i][j]; + vint4 weight = select(vint4(plane1_weights[tix]), vint4(plane2_weights[tix]), plane2_mask); + vint4 color = lerp_color_int(decode_mode, ep0, ep1, weight); + vfloat4 colorf = decode_texel(color, lns_mask); + + blk.data_r[tix] = colorf.lane<0>(); + blk.data_g[tix] = colorf.lane<1>(); + blk.data_b[tix] = colorf.lane<2>(); + blk.data_a[tix] = colorf.lane<3>(); + } + } +} + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/* See header for documentation. */ +float compute_symbolic_block_difference_2plane( + const astcenc_config& config, + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const image_block& blk +) { + // If we detected an error-block, blow up immediately. + if (scb.block_type == SYM_BTYPE_ERROR) + { + return ERROR_CALC_DEFAULT; + } + + assert(scb.block_mode >= 0); + assert(scb.partition_count == 1); + assert(bsd.get_block_mode(scb.block_mode).is_dual_plane == 1); + + // Get the appropriate block descriptor + const block_mode& bm = bsd.get_block_mode(scb.block_mode); + const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode); + + // Unquantize and undecimate the weights + int plane1_weights[BLOCK_MAX_TEXELS]; + int plane2_weights[BLOCK_MAX_TEXELS]; + unpack_weights(bsd, scb, di, true, plane1_weights, plane2_weights); + + vmask4 plane2_mask = vint4::lane_id() == vint4(scb.plane2_component); + + vfloat4 summa = vfloat4::zero(); + + // Decode the color endpoints for this partition + vint4 ep0; + vint4 ep1; + bool rgb_lns; + bool a_lns; + + unpack_color_endpoints(config.profile, + scb.color_formats[0], + scb.color_values[0], + rgb_lns, a_lns, + ep0, ep1); + + // Unpack and compute error for each texel in the partition + unsigned int texel_count = bsd.texel_count; + for (unsigned int i = 0; i < texel_count; i++) + { + vint4 weight = select(vint4(plane1_weights[i]), vint4(plane2_weights[i]), plane2_mask); + vint4 colori = lerp_color_int(config.profile, ep0, ep1, weight); + + vfloat4 color = int_to_float(colori); + vfloat4 oldColor = blk.texel(i); + + // Compare error using a perceptual decode metric for RGBM textures + if (config.flags & ASTCENC_FLG_MAP_RGBM) + { + // Fail encodings that result in zero weight M pixels. Note that this can cause + // "interesting" artifacts if we reject all useful encodings - we typically get max + // brightness encodings instead which look just as bad. We recommend users apply a + // bias to their stored M value, limiting the lower value to 16 or 32 to avoid + // getting small M values post-quantization, but we can't prove it would never + // happen, especially at low bit rates ... + if (color.lane<3>() == 0.0f) + { + return -ERROR_CALC_DEFAULT; + } + + // Compute error based on decoded RGBM color + color = vfloat4( + color.lane<0>() * color.lane<3>() * config.rgbm_m_scale, + color.lane<1>() * color.lane<3>() * config.rgbm_m_scale, + color.lane<2>() * color.lane<3>() * config.rgbm_m_scale, + 1.0f + ); + + oldColor = vfloat4( + oldColor.lane<0>() * oldColor.lane<3>() * config.rgbm_m_scale, + oldColor.lane<1>() * oldColor.lane<3>() * config.rgbm_m_scale, + oldColor.lane<2>() * oldColor.lane<3>() * config.rgbm_m_scale, + 1.0f + ); + } + + vfloat4 error = oldColor - color; + error = min(abs(error), 1e15f); + error = error * error; + + summa += min(dot(error, blk.channel_weight), ERROR_CALC_DEFAULT); + } + + return summa.lane<0>(); +} + +/* See header for documentation. */ +float compute_symbolic_block_difference_1plane( + const astcenc_config& config, + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const image_block& blk +) { + assert(bsd.get_block_mode(scb.block_mode).is_dual_plane == 0); + + // If we detected an error-block, blow up immediately. + if (scb.block_type == SYM_BTYPE_ERROR) + { + return ERROR_CALC_DEFAULT; + } + + assert(scb.block_mode >= 0); + + // Get the appropriate partition-table entry + unsigned int partition_count = scb.partition_count; + const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index); + + // Get the appropriate block descriptor + const block_mode& bm = bsd.get_block_mode(scb.block_mode); + const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode); + + // Unquantize and undecimate the weights + int plane1_weights[BLOCK_MAX_TEXELS]; + unpack_weights(bsd, scb, di, false, plane1_weights, nullptr); + + vfloat4 summa = vfloat4::zero(); + for (unsigned int i = 0; i < partition_count; i++) + { + // Decode the color endpoints for this partition + vint4 ep0; + vint4 ep1; + bool rgb_lns; + bool a_lns; + + unpack_color_endpoints(config.profile, + scb.color_formats[i], + scb.color_values[i], + rgb_lns, a_lns, + ep0, ep1); + + // Unpack and compute error for each texel in the partition + unsigned int texel_count = pi.partition_texel_count[i]; + for (unsigned int j = 0; j < texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + vint4 colori = lerp_color_int(config.profile, ep0, ep1, + vint4(plane1_weights[tix])); + + vfloat4 color = int_to_float(colori); + vfloat4 oldColor = blk.texel(tix); + + // Compare error using a perceptual decode metric for RGBM textures + if (config.flags & ASTCENC_FLG_MAP_RGBM) + { + // Fail encodings that result in zero weight M pixels. Note that this can cause + // "interesting" artifacts if we reject all useful encodings - we typically get max + // brightness encodings instead which look just as bad. We recommend users apply a + // bias to their stored M value, limiting the lower value to 16 or 32 to avoid + // getting small M values post-quantization, but we can't prove it would never + // happen, especially at low bit rates ... + if (color.lane<3>() == 0.0f) + { + return -ERROR_CALC_DEFAULT; + } + + // Compute error based on decoded RGBM color + color = vfloat4( + color.lane<0>() * color.lane<3>() * config.rgbm_m_scale, + color.lane<1>() * color.lane<3>() * config.rgbm_m_scale, + color.lane<2>() * color.lane<3>() * config.rgbm_m_scale, + 1.0f + ); + + oldColor = vfloat4( + oldColor.lane<0>() * oldColor.lane<3>() * config.rgbm_m_scale, + oldColor.lane<1>() * oldColor.lane<3>() * config.rgbm_m_scale, + oldColor.lane<2>() * oldColor.lane<3>() * config.rgbm_m_scale, + 1.0f + ); + } + + vfloat4 error = oldColor - color; + error = min(abs(error), 1e15f); + error = error * error; + + summa += min(dot(error, blk.channel_weight), ERROR_CALC_DEFAULT); + } + } + + return summa.lane<0>(); +} + +/* See header for documentation. */ +float compute_symbolic_block_difference_1plane_1partition( + const astcenc_config& config, + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const image_block& blk +) { + // If we detected an error-block, blow up immediately. + if (scb.block_type == SYM_BTYPE_ERROR) + { + return ERROR_CALC_DEFAULT; + } + + assert(scb.block_mode >= 0); + assert(bsd.get_partition_info(scb.partition_count, scb.partition_index).partition_count == 1); + + // Get the appropriate block descriptor + const block_mode& bm = bsd.get_block_mode(scb.block_mode); + const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode); + + // Unquantize and undecimate the weights + alignas(ASTCENC_VECALIGN) int plane1_weights[BLOCK_MAX_TEXELS]; + unpack_weights(bsd, scb, di, false, plane1_weights, nullptr); + + // Decode the color endpoints for this partition + vint4 ep0; + vint4 ep1; + bool rgb_lns; + bool a_lns; + + unpack_color_endpoints(config.profile, + scb.color_formats[0], + scb.color_values[0], + rgb_lns, a_lns, + ep0, ep1); + + + // Pre-shift sRGB so things round correctly + if (config.profile == ASTCENC_PRF_LDR_SRGB) + { + ep0 = asr<8>(ep0); + ep1 = asr<8>(ep1); + } + + // Unpack and compute error for each texel in the partition + vfloatacc summav = vfloatacc::zero(); + + vint lane_id = vint::lane_id(); + vint srgb_scale(config.profile == ASTCENC_PRF_LDR_SRGB ? 257 : 1); + + unsigned int texel_count = bsd.texel_count; + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Compute EP1 contribution + vint weight1 = vint::loada(plane1_weights + i); + vint ep1_r = vint(ep1.lane<0>()) * weight1; + vint ep1_g = vint(ep1.lane<1>()) * weight1; + vint ep1_b = vint(ep1.lane<2>()) * weight1; + vint ep1_a = vint(ep1.lane<3>()) * weight1; + + // Compute EP0 contribution + vint weight0 = vint(64) - weight1; + vint ep0_r = vint(ep0.lane<0>()) * weight0; + vint ep0_g = vint(ep0.lane<1>()) * weight0; + vint ep0_b = vint(ep0.lane<2>()) * weight0; + vint ep0_a = vint(ep0.lane<3>()) * weight0; + + // Shift so things round correctly + vint colori_r = asr<6>(ep0_r + ep1_r + vint(32)) * srgb_scale; + vint colori_g = asr<6>(ep0_g + ep1_g + vint(32)) * srgb_scale; + vint colori_b = asr<6>(ep0_b + ep1_b + vint(32)) * srgb_scale; + vint colori_a = asr<6>(ep0_a + ep1_a + vint(32)) * srgb_scale; + + // Compute color diff + vfloat color_r = int_to_float(colori_r); + vfloat color_g = int_to_float(colori_g); + vfloat color_b = int_to_float(colori_b); + vfloat color_a = int_to_float(colori_a); + + vfloat color_orig_r = loada(blk.data_r + i); + vfloat color_orig_g = loada(blk.data_g + i); + vfloat color_orig_b = loada(blk.data_b + i); + vfloat color_orig_a = loada(blk.data_a + i); + + vfloat color_error_r = min(abs(color_orig_r - color_r), vfloat(1e15f)); + vfloat color_error_g = min(abs(color_orig_g - color_g), vfloat(1e15f)); + vfloat color_error_b = min(abs(color_orig_b - color_b), vfloat(1e15f)); + vfloat color_error_a = min(abs(color_orig_a - color_a), vfloat(1e15f)); + + // Compute squared error metric + color_error_r = color_error_r * color_error_r; + color_error_g = color_error_g * color_error_g; + color_error_b = color_error_b * color_error_b; + color_error_a = color_error_a * color_error_a; + + vfloat metric = color_error_r * blk.channel_weight.lane<0>() + + color_error_g * blk.channel_weight.lane<1>() + + color_error_b * blk.channel_weight.lane<2>() + + color_error_a * blk.channel_weight.lane<3>(); + + // Mask off bad lanes + vmask mask = lane_id < vint(texel_count); + lane_id += vint(ASTCENC_SIMD_WIDTH); + haccumulate(summav, metric, mask); + } + + return hadd_s(summav); +} + +#endif diff --git a/thirdparty/astcenc/astcenc_diagnostic_trace.cpp b/thirdparty/astcenc/astcenc_diagnostic_trace.cpp new file mode 100644 index 0000000000..7fa7ab1a8b --- /dev/null +++ b/thirdparty/astcenc/astcenc_diagnostic_trace.cpp @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2021-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for the library entrypoint. + */ + +#if defined(ASTCENC_DIAGNOSTICS) + +#include <cassert> +#include <cstdarg> +#include <cstdio> +#include <string> + +#include "astcenc_diagnostic_trace.h" + +/** @brief The global trace logger. */ +static TraceLog* g_TraceLog = nullptr; + +/** @brief The JSON indentation level. */ +static const size_t g_trace_indent = 2; + +TraceLog::TraceLog( + const char* file_name): + m_file(file_name, std::ofstream::out | std::ofstream::binary) +{ + assert(!g_TraceLog); + g_TraceLog = this; + m_root = new TraceNode("root"); +} + +/* See header for documentation. */ +TraceNode* TraceLog::get_current_leaf() +{ + if (m_stack.size()) + { + return m_stack.back(); + } + + return nullptr; +} + +/* See header for documentation. */ +size_t TraceLog::get_depth() +{ + return m_stack.size(); +} + +/* See header for documentation. */ +TraceLog::~TraceLog() +{ + assert(g_TraceLog == this); + delete m_root; + g_TraceLog = nullptr; +} + +/* See header for documentation. */ +TraceNode::TraceNode( + const char* format, + ... +) { + // Format the name string + constexpr size_t bufsz = 256; + char buffer[bufsz]; + + va_list args; + va_start (args, format); + vsnprintf (buffer, bufsz, format, args); + va_end (args); + + // Guarantee there is a nul terminator + buffer[bufsz - 1] = 0; + + // Generate the node + TraceNode* parent = g_TraceLog->get_current_leaf(); + size_t depth = g_TraceLog->get_depth(); + g_TraceLog->m_stack.push_back(this); + + bool comma = parent && parent->m_attrib_count; + auto& out = g_TraceLog->m_file; + + if (parent) + { + parent->m_attrib_count++; + } + + if (comma) + { + out << ','; + } + + if (depth) + { + out << '\n'; + } + + size_t out_indent = (depth * 2) * g_trace_indent; + size_t in_indent = (depth * 2 + 1) * g_trace_indent; + + std::string out_indents(""); + if (out_indent) + { + out_indents = std::string(out_indent, ' '); + } + + std::string in_indents(in_indent, ' '); + + out << out_indents << "[ \"node\", \"" << buffer << "\",\n"; + out << in_indents << "["; +} + +/* See header for documentation. */ +void TraceNode::add_attrib( + std::string type, + std::string key, + std::string value +) { + (void)type; + + size_t depth = g_TraceLog->get_depth(); + size_t indent = (depth * 2) * g_trace_indent; + auto& out = g_TraceLog->m_file; + bool comma = m_attrib_count; + m_attrib_count++; + + if (comma) + { + out << ','; + } + + out << '\n'; + out << std::string(indent, ' ') << "[ " + << "\"" << key << "\", " + << value << " ]"; +} + +/* See header for documentation. */ +TraceNode::~TraceNode() +{ + g_TraceLog->m_stack.pop_back(); + + auto& out = g_TraceLog->m_file; + size_t depth = g_TraceLog->get_depth(); + size_t out_indent = (depth * 2) * g_trace_indent; + size_t in_indent = (depth * 2 + 1) * g_trace_indent; + + std::string out_indents(""); + if (out_indent) + { + out_indents = std::string(out_indent, ' '); + } + + std::string in_indents(in_indent, ' '); + + if (m_attrib_count) + { + out << "\n" << in_indents; + } + out << "]\n"; + + out << out_indents << "]"; +} + +/* See header for documentation. */ +void trace_add_data( + const char* key, + const char* format, + ... +) { + constexpr size_t bufsz = 256; + char buffer[bufsz]; + + va_list args; + va_start (args, format); + vsnprintf (buffer, bufsz, format, args); + va_end (args); + + // Guarantee there is a nul terminator + buffer[bufsz - 1] = 0; + + std::string value = "\"" + std::string(buffer) + "\""; + + TraceNode* node = g_TraceLog->get_current_leaf(); + node->add_attrib("str", key, value); +} + +/* See header for documentation. */ +void trace_add_data( + const char* key, + float value +) { + char buffer[256]; + sprintf(buffer, "%.20g", (double)value); + TraceNode* node = g_TraceLog->get_current_leaf(); + node->add_attrib("float", key, buffer); +} + +/* See header for documentation. */ +void trace_add_data( + const char* key, + int value +) { + TraceNode* node = g_TraceLog->get_current_leaf(); + node->add_attrib("int", key, std::to_string(value)); +} + +/* See header for documentation. */ +void trace_add_data( + const char* key, + unsigned int value +) { + TraceNode* node = g_TraceLog->get_current_leaf(); + node->add_attrib("int", key, std::to_string(value)); +} + +#endif diff --git a/thirdparty/astcenc/astcenc_diagnostic_trace.h b/thirdparty/astcenc/astcenc_diagnostic_trace.h new file mode 100644 index 0000000000..f5586b0ad5 --- /dev/null +++ b/thirdparty/astcenc/astcenc_diagnostic_trace.h @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2021-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief This module provides a set of diagnostic tracing utilities. + * + * Overview + * ======== + * + * The built-in diagnostic trace tool generates a hierarchical JSON tree structure. The tree + * hierarchy contains three levels: + * + * - block + * - pass + * - candidate + * + * One block node exists for each compressed block in the image. One pass node exists for each major + * pass (N partition, M planes, O components) applied to a block. One candidate node exists for each + * encoding candidate trialed for a pass. + * + * Each node contains both the hierarchy but also a number of attributes which explain the behavior. + * For example, the block node contains the block coordinates in the image, the pass explains the + * pass configuration, and the candidate will explain the candidate encoding such as weight + * decimation, refinement error, etc. + * + * Trace Nodes are designed as scope-managed C++ objects with stack-like push/pop behavior. + * Constructing a trace node on the stack will automatically add it to the current node as a child, + * and then make it the current node. Destroying the current node will pop the stack and set the + * parent to the current node. This provides a robust mechanism for ensuring reliable nesting in the + * tree structure. + * + * A set of utility macros are provided to add attribute annotations to the current trace node. + * + * Usage + * ===== + * + * Create Trace Nodes on the stack using the @c TRACE_NODE() macro. This will compile-out completely + * in builds with diagnostics disabled. + * + * Add annotations to the current trace node using the @c trace_add_data() macro. This will + * similarly compile out completely in builds with diagnostics disabled. + * + * If you need to add additional code to support diagnostics-only behavior wrap + * it in preprocessor guards: + * + * #if defined(ASTCENC_DIAGNOSTICS) + * #endif + */ + +#ifndef ASTCENC_DIAGNOSTIC_TRACE_INCLUDED +#define ASTCENC_DIAGNOSTIC_TRACE_INCLUDED + +#if defined(ASTCENC_DIAGNOSTICS) + +#include <iostream> +#include <fstream> +#include <vector> + +/** + * @brief Class representing a single node in the trace hierarchy. + */ +class TraceNode +{ +public: + /** + * @brief Construct a new node. + * + * Constructing a node will push to the the top of the stack, automatically making it a child of + * the current node, and then setting it to become the current node. + * + * @param format The format template for the node name. + * @param ... The format parameters. + */ + TraceNode(const char* format, ...); + + /** + * @brief Add an attribute to this node. + * + * Note that no quoting is applied to the @c value, so if quoting is needed it must be done by + * the caller. + * + * @param type The type of the attribute. + * @param key The key of the attribute. + * @param value The value of the attribute. + */ + void add_attrib(std::string type, std::string key, std::string value); + + /** + * @brief Destroy this node. + * + * Destroying a node will pop it from the top of the stack, making its parent the current node. + * It is invalid behavior to destroy a node that is not the current node; usage must conform to + * stack push-pop semantics. + */ + ~TraceNode(); + + /** + * @brief The number of attributes and child nodes in this node. + */ + unsigned int m_attrib_count { 0 }; +}; + +/** + * @brief Class representing the trace log file being written. + */ +class TraceLog +{ +public: + /** + * @brief Create a new trace log. + * + * The trace log is global; there can be only one at a time. + * + * @param file_name The name of the file to write. + */ + TraceLog(const char* file_name); + + /** + * @brief Detroy the trace log. + * + * Trace logs MUST be cleanly destroyed to ensure the file gets written. + */ + ~TraceLog(); + + /** + * @brief Get the current child node. + * + * @return The current leaf node. + */ + TraceNode* get_current_leaf(); + + /** + * @brief Get the stack depth of the current child node. + * + * @return The current leaf node stack depth. + */ + size_t get_depth(); + + /** + * @brief The file stream to write to. + */ + std::ofstream m_file; + + /** + * @brief The stack of nodes (newest at the back). + */ + std::vector<TraceNode*> m_stack; + +private: + /** + * @brief The root node in the JSON file. + */ + TraceNode* m_root; +}; + +/** + * @brief Utility macro to create a trace node on the stack. + * + * @param name The variable name to use. + * @param ... The name template and format parameters. + */ +#define TRACE_NODE(name, ...) TraceNode name(__VA_ARGS__); + +/** + * @brief Add a string annotation to the current node. + * + * @param key The name of the attribute. + * @param format The format template for the attribute value. + * @param ... The format parameters. + */ +void trace_add_data(const char* key, const char* format, ...); + +/** + * @brief Add a float annotation to the current node. + * + * @param key The name of the attribute. + * @param value The value of the attribute. + */ +void trace_add_data(const char* key, float value); + +/** + * @brief Add an integer annotation to the current node. + * + * @param key The name of the attribute. + * @param value The value of the attribute. + */ +void trace_add_data(const char* key, int value); + +/** + * @brief Add an unsigned integer annotation to the current node. + * + * @param key The name of the attribute. + * @param value The value of the attribute. + */ +void trace_add_data(const char* key, unsigned int value); + +#else + +#define TRACE_NODE(name, ...) + +#define trace_add_data(...) + +#endif + +#endif diff --git a/thirdparty/astcenc/astcenc_entry.cpp b/thirdparty/astcenc/astcenc_entry.cpp new file mode 100644 index 0000000000..e59f1fe61a --- /dev/null +++ b/thirdparty/astcenc/astcenc_entry.cpp @@ -0,0 +1,1427 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for the library entrypoint. + */ + +#include <array> +#include <cstring> +#include <new> + +#include "astcenc.h" +#include "astcenc_internal_entry.h" +#include "astcenc_diagnostic_trace.h" + +/** + * @brief Record of the quality tuning parameter values. + * + * See the @c astcenc_config structure for detailed parameter documentation. + * + * Note that the mse_overshoot entries are scaling factors relative to the base MSE to hit db_limit. + * A 20% overshoot is harder to hit for a higher base db_limit, so we may actually use lower ratios + * for the more through search presets because the underlying db_limit is so much higher. + */ +struct astcenc_preset_config +{ + float quality; + unsigned int tune_partition_count_limit; + unsigned int tune_2partition_index_limit; + unsigned int tune_3partition_index_limit; + unsigned int tune_4partition_index_limit; + unsigned int tune_block_mode_limit; + unsigned int tune_refinement_limit; + unsigned int tune_candidate_limit; + unsigned int tune_2partitioning_candidate_limit; + unsigned int tune_3partitioning_candidate_limit; + unsigned int tune_4partitioning_candidate_limit; + float tune_db_limit_a_base; + float tune_db_limit_b_base; + float tune_mse_overshoot; + float tune_2_partition_early_out_limit_factor; + float tune_3_partition_early_out_limit_factor; + float tune_2_plane_early_out_limit_correlation; +}; + +/** + * @brief The static presets for high bandwidth encodings (x < 25 texels per block). + */ +static const std::array<astcenc_preset_config, 6> preset_configs_high {{ + { + ASTCENC_PRE_FASTEST, + 2, 10, 6, 4, 43, 2, 2, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.85f + }, { + ASTCENC_PRE_FAST, + 3, 18, 10, 8, 55, 3, 3, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.90f + }, { + ASTCENC_PRE_MEDIUM, + 4, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 2.5f, 1.1f, 1.05f, 0.95f + }, { + ASTCENC_PRE_THOROUGH, + 4, 82, 60, 30, 94, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.35f, 1.15f, 0.97f + }, { + ASTCENC_PRE_VERYTHOROUGH, + 4, 256, 128, 64, 98, 4, 6, 20, 14, 8, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f + }, { + ASTCENC_PRE_EXHAUSTIVE, + 4, 512, 512, 512, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f + } +}}; + +/** + * @brief The static presets for medium bandwidth encodings (25 <= x < 64 texels per block). + */ +static const std::array<astcenc_preset_config, 6> preset_configs_mid {{ + { + ASTCENC_PRE_FASTEST, + 2, 10, 6, 4, 43, 2, 2, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.80f + }, { + ASTCENC_PRE_FAST, + 3, 18, 12, 10, 55, 3, 3, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.85f + }, { + ASTCENC_PRE_MEDIUM, + 4, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 3.0f, 1.1f, 1.05f, 0.90f + }, { + ASTCENC_PRE_THOROUGH, + 4, 82, 60, 30, 94, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.4f, 1.2f, 0.95f + }, { + ASTCENC_PRE_VERYTHOROUGH, + 4, 256, 128, 64, 98, 4, 6, 12, 8, 3, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f + }, { + ASTCENC_PRE_EXHAUSTIVE, + 4, 256, 256, 256, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f + } +}}; + +/** + * @brief The static presets for low bandwidth encodings (64 <= x texels per block). + */ +static const std::array<astcenc_preset_config, 6> preset_configs_low {{ + { + ASTCENC_PRE_FASTEST, + 2, 10, 6, 4, 40, 2, 2, 2, 2, 2, 85.0f, 63.0f, 3.5f, 1.0f, 1.0f, 0.80f + }, { + ASTCENC_PRE_FAST, + 2, 18, 12, 10, 55, 3, 3, 2, 2, 2, 85.0f, 63.0f, 3.5f, 1.0f, 1.0f, 0.85f + }, { + ASTCENC_PRE_MEDIUM, + 3, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 3.5f, 1.1f, 1.05f, 0.90f + }, { + ASTCENC_PRE_THOROUGH, + 4, 82, 60, 30, 93, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.3f, 1.2f, 0.97f + }, { + ASTCENC_PRE_VERYTHOROUGH, + 4, 256, 128, 64, 98, 4, 6, 9, 5, 2, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f + }, { + ASTCENC_PRE_EXHAUSTIVE, + 4, 256, 256, 256, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f + } +}}; + +/** + * @brief Validate CPU floating point meets assumptions made in the codec. + * + * The codec is written with the assumption that a float threaded through the @c if32 union will be + * stored and reloaded as a 32-bit IEEE-754 float with round-to-nearest rounding. This is always the + * case in an IEEE-754 compliant system, however not every system or compilation mode is actually + * IEEE-754 compliant. This normally fails if the code is compiled with fast math enabled. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_cpu_float() +{ + if32 p; + volatile float xprec_testval = 2.51f; + p.f = xprec_testval + 12582912.0f; + float q = p.f - 12582912.0f; + + if (q != 3.0f) + { + return ASTCENC_ERR_BAD_CPU_FLOAT; + } + + return ASTCENC_SUCCESS; +} + +/** + * @brief Validate CPU ISA support meets the requirements of this build of the library. + * + * Each library build is statically compiled for a particular set of CPU ISA features, such as the + * SIMD support or other ISA extensions such as POPCNT. This function checks that the host CPU + * actually supports everything this build needs. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_cpu_isa() +{ + #if ASTCENC_SSE >= 41 + if (!cpu_supports_sse41()) + { + return ASTCENC_ERR_BAD_CPU_ISA; + } + #endif + + #if ASTCENC_POPCNT >= 1 + if (!cpu_supports_popcnt()) + { + return ASTCENC_ERR_BAD_CPU_ISA; + } + #endif + + #if ASTCENC_F16C >= 1 + if (!cpu_supports_f16c()) + { + return ASTCENC_ERR_BAD_CPU_ISA; + } + #endif + + #if ASTCENC_AVX >= 2 + if (!cpu_supports_avx2()) + { + return ASTCENC_ERR_BAD_CPU_ISA; + } + #endif + + return ASTCENC_SUCCESS; +} + +/** + * @brief Validate config profile. + * + * @param profile The profile to check. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_profile( + astcenc_profile profile +) { + // Values in this enum are from an external user, so not guaranteed to be + // bounded to the enum values + switch (static_cast<int>(profile)) + { + case ASTCENC_PRF_LDR_SRGB: + case ASTCENC_PRF_LDR: + case ASTCENC_PRF_HDR_RGB_LDR_A: + case ASTCENC_PRF_HDR: + return ASTCENC_SUCCESS; + default: + return ASTCENC_ERR_BAD_PROFILE; + } +} + +/** + * @brief Validate block size. + * + * @param block_x The block x dimensions. + * @param block_y The block y dimensions. + * @param block_z The block z dimensions. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_block_size( + unsigned int block_x, + unsigned int block_y, + unsigned int block_z +) { + // Test if this is a legal block size at all + bool is_legal = (((block_z <= 1) && is_legal_2d_block_size(block_x, block_y)) || + ((block_z >= 2) && is_legal_3d_block_size(block_x, block_y, block_z))); + if (!is_legal) + { + return ASTCENC_ERR_BAD_BLOCK_SIZE; + } + + // Test if this build has sufficient capacity for this block size + bool have_capacity = (block_x * block_y * block_z) <= BLOCK_MAX_TEXELS; + if (!have_capacity) + { + return ASTCENC_ERR_NOT_IMPLEMENTED; + } + + return ASTCENC_SUCCESS; +} + +/** + * @brief Validate flags. + * + * @param flags The flags to check. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_flags( + unsigned int flags +) { + // Flags field must not contain any unknown flag bits + unsigned int exMask = ~ASTCENC_ALL_FLAGS; + if (popcount(flags & exMask) != 0) + { + return ASTCENC_ERR_BAD_FLAGS; + } + + // Flags field must only contain at most a single map type + exMask = ASTCENC_FLG_MAP_NORMAL + | ASTCENC_FLG_MAP_RGBM; + if (popcount(flags & exMask) > 1) + { + return ASTCENC_ERR_BAD_FLAGS; + } + + return ASTCENC_SUCCESS; +} + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Validate single channel compression swizzle. + * + * @param swizzle The swizzle to check. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_compression_swz( + astcenc_swz swizzle +) { + // Not all enum values are handled; SWZ_Z is invalid for compression + switch (static_cast<int>(swizzle)) + { + case ASTCENC_SWZ_R: + case ASTCENC_SWZ_G: + case ASTCENC_SWZ_B: + case ASTCENC_SWZ_A: + case ASTCENC_SWZ_0: + case ASTCENC_SWZ_1: + return ASTCENC_SUCCESS; + default: + return ASTCENC_ERR_BAD_SWIZZLE; + } +} + +/** + * @brief Validate overall compression swizzle. + * + * @param swizzle The swizzle to check. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_compression_swizzle( + const astcenc_swizzle& swizzle +) { + if (validate_compression_swz(swizzle.r) || + validate_compression_swz(swizzle.g) || + validate_compression_swz(swizzle.b) || + validate_compression_swz(swizzle.a)) + { + return ASTCENC_ERR_BAD_SWIZZLE; + } + + return ASTCENC_SUCCESS; +} +#endif + +/** + * @brief Validate single channel decompression swizzle. + * + * @param swizzle The swizzle to check. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_decompression_swz( + astcenc_swz swizzle +) { + // Values in this enum are from an external user, so not guaranteed to be + // bounded to the enum values + switch (static_cast<int>(swizzle)) + { + case ASTCENC_SWZ_R: + case ASTCENC_SWZ_G: + case ASTCENC_SWZ_B: + case ASTCENC_SWZ_A: + case ASTCENC_SWZ_0: + case ASTCENC_SWZ_1: + case ASTCENC_SWZ_Z: + return ASTCENC_SUCCESS; + default: + return ASTCENC_ERR_BAD_SWIZZLE; + } +} + +/** + * @brief Validate overall decompression swizzle. + * + * @param swizzle The swizzle to check. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_decompression_swizzle( + const astcenc_swizzle& swizzle +) { + if (validate_decompression_swz(swizzle.r) || + validate_decompression_swz(swizzle.g) || + validate_decompression_swz(swizzle.b) || + validate_decompression_swz(swizzle.a)) + { + return ASTCENC_ERR_BAD_SWIZZLE; + } + + return ASTCENC_SUCCESS; +} + +/** + * Validate that an incoming configuration is in-spec. + * + * This function can respond in two ways: + * + * * Numerical inputs that have valid ranges are clamped to those valid ranges. No error is thrown + * for out-of-range inputs in this case. + * * Numerical inputs and logic inputs are are logically invalid and which make no sense + * algorithmically will return an error. + * + * @param[in,out] config The input compressor configuration. + * + * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + */ +static astcenc_error validate_config( + astcenc_config &config +) { + astcenc_error status; + + status = validate_profile(config.profile); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + status = validate_flags(config.flags); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + status = validate_block_size(config.block_x, config.block_y, config.block_z); + if (status != ASTCENC_SUCCESS) + { + return status; + } + +#if defined(ASTCENC_DECOMPRESS_ONLY) + // Decompress-only builds only support decompress-only contexts + if (!(config.flags & ASTCENC_FLG_DECOMPRESS_ONLY)) + { + return ASTCENC_ERR_BAD_PARAM; + } +#endif + + config.rgbm_m_scale = astc::max(config.rgbm_m_scale, 1.0f); + + config.tune_partition_count_limit = astc::clamp(config.tune_partition_count_limit, 1u, 4u); + config.tune_2partition_index_limit = astc::clamp(config.tune_2partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS); + config.tune_3partition_index_limit = astc::clamp(config.tune_3partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS); + config.tune_4partition_index_limit = astc::clamp(config.tune_4partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS); + config.tune_block_mode_limit = astc::clamp(config.tune_block_mode_limit, 1u, 100u); + config.tune_refinement_limit = astc::max(config.tune_refinement_limit, 1u); + config.tune_candidate_limit = astc::clamp(config.tune_candidate_limit, 1u, TUNE_MAX_TRIAL_CANDIDATES); + config.tune_2partitioning_candidate_limit = astc::clamp(config.tune_2partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES); + config.tune_3partitioning_candidate_limit = astc::clamp(config.tune_3partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES); + config.tune_4partitioning_candidate_limit = astc::clamp(config.tune_4partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES); + config.tune_db_limit = astc::max(config.tune_db_limit, 0.0f); + config.tune_mse_overshoot = astc::max(config.tune_mse_overshoot, 1.0f); + config.tune_2_partition_early_out_limit_factor = astc::max(config.tune_2_partition_early_out_limit_factor, 0.0f); + config.tune_3_partition_early_out_limit_factor = astc::max(config.tune_3_partition_early_out_limit_factor, 0.0f); + config.tune_2_plane_early_out_limit_correlation = astc::max(config.tune_2_plane_early_out_limit_correlation, 0.0f); + + // Specifying a zero weight color component is not allowed; force to small value + float max_weight = astc::max(astc::max(config.cw_r_weight, config.cw_g_weight), + astc::max(config.cw_b_weight, config.cw_a_weight)); + if (max_weight > 0.0f) + { + max_weight /= 1000.0f; + config.cw_r_weight = astc::max(config.cw_r_weight, max_weight); + config.cw_g_weight = astc::max(config.cw_g_weight, max_weight); + config.cw_b_weight = astc::max(config.cw_b_weight, max_weight); + config.cw_a_weight = astc::max(config.cw_a_weight, max_weight); + } + // If all color components error weights are zero then return an error + else + { + return ASTCENC_ERR_BAD_PARAM; + } + + return ASTCENC_SUCCESS; +} + +/* See header for documentation. */ +astcenc_error astcenc_config_init( + astcenc_profile profile, + unsigned int block_x, + unsigned int block_y, + unsigned int block_z, + float quality, + unsigned int flags, + astcenc_config* configp +) { + astcenc_error status; + + // Check basic library compatibility options here so they are checked early. Note, these checks + // are repeated in context_alloc for cases where callers use a manually defined config struct + status = validate_cpu_isa(); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + status = validate_cpu_float(); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + // Zero init all config fields; although most of will be over written + astcenc_config& config = *configp; + std::memset(&config, 0, sizeof(config)); + + // Process the block size + block_z = astc::max(block_z, 1u); // For 2D blocks Z==0 is accepted, but convert to 1 + status = validate_block_size(block_x, block_y, block_z); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + config.block_x = block_x; + config.block_y = block_y; + config.block_z = block_z; + + float texels = static_cast<float>(block_x * block_y * block_z); + float ltexels = logf(texels) / logf(10.0f); + + // Process the performance quality level or preset; note that this must be done before we + // process any additional settings, such as color profile and flags, which may replace some of + // these settings with more use case tuned values + if (quality < ASTCENC_PRE_FASTEST || + quality > ASTCENC_PRE_EXHAUSTIVE) + { + return ASTCENC_ERR_BAD_QUALITY; + } + + static const std::array<astcenc_preset_config, 6>* preset_configs; + int texels_int = block_x * block_y * block_z; + if (texels_int < 25) + { + preset_configs = &preset_configs_high; + } + else if (texels_int < 64) + { + preset_configs = &preset_configs_mid; + } + else + { + preset_configs = &preset_configs_low; + } + + // Determine which preset to use, or which pair to interpolate + size_t start; + size_t end; + for (end = 0; end < preset_configs->size(); end++) + { + if ((*preset_configs)[end].quality >= quality) + { + break; + } + } + + start = end == 0 ? 0 : end - 1; + + // Start and end node are the same - so just transfer the values. + if (start == end) + { + config.tune_partition_count_limit = (*preset_configs)[start].tune_partition_count_limit; + config.tune_2partition_index_limit = (*preset_configs)[start].tune_2partition_index_limit; + config.tune_3partition_index_limit = (*preset_configs)[start].tune_3partition_index_limit; + config.tune_4partition_index_limit = (*preset_configs)[start].tune_4partition_index_limit; + config.tune_block_mode_limit = (*preset_configs)[start].tune_block_mode_limit; + config.tune_refinement_limit = (*preset_configs)[start].tune_refinement_limit; + config.tune_candidate_limit = astc::min((*preset_configs)[start].tune_candidate_limit, TUNE_MAX_TRIAL_CANDIDATES); + config.tune_2partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_2partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES); + config.tune_3partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_3partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES); + config.tune_4partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_4partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES); + config.tune_db_limit = astc::max((*preset_configs)[start].tune_db_limit_a_base - 35 * ltexels, + (*preset_configs)[start].tune_db_limit_b_base - 19 * ltexels); + + config.tune_mse_overshoot = (*preset_configs)[start].tune_mse_overshoot; + + config.tune_2_partition_early_out_limit_factor = (*preset_configs)[start].tune_2_partition_early_out_limit_factor; + config.tune_3_partition_early_out_limit_factor =(*preset_configs)[start].tune_3_partition_early_out_limit_factor; + config.tune_2_plane_early_out_limit_correlation = (*preset_configs)[start].tune_2_plane_early_out_limit_correlation; + } + // Start and end node are not the same - so interpolate between them + else + { + auto& node_a = (*preset_configs)[start]; + auto& node_b = (*preset_configs)[end]; + + float wt_range = node_b.quality - node_a.quality; + assert(wt_range > 0); + + // Compute interpolation factors + float wt_node_a = (node_b.quality - quality) / wt_range; + float wt_node_b = (quality - node_a.quality) / wt_range; + + #define LERP(param) ((node_a.param * wt_node_a) + (node_b.param * wt_node_b)) + #define LERPI(param) astc::flt2int_rtn(\ + (static_cast<float>(node_a.param) * wt_node_a) + \ + (static_cast<float>(node_b.param) * wt_node_b)) + #define LERPUI(param) static_cast<unsigned int>(LERPI(param)) + + config.tune_partition_count_limit = LERPI(tune_partition_count_limit); + config.tune_2partition_index_limit = LERPI(tune_2partition_index_limit); + config.tune_3partition_index_limit = LERPI(tune_3partition_index_limit); + config.tune_4partition_index_limit = LERPI(tune_4partition_index_limit); + config.tune_block_mode_limit = LERPI(tune_block_mode_limit); + config.tune_refinement_limit = LERPI(tune_refinement_limit); + config.tune_candidate_limit = astc::min(LERPUI(tune_candidate_limit), + TUNE_MAX_TRIAL_CANDIDATES); + config.tune_2partitioning_candidate_limit = astc::min(LERPUI(tune_2partitioning_candidate_limit), + BLOCK_MAX_PARTITIONINGS); + config.tune_3partitioning_candidate_limit = astc::min(LERPUI(tune_3partitioning_candidate_limit), + BLOCK_MAX_PARTITIONINGS); + config.tune_4partitioning_candidate_limit = astc::min(LERPUI(tune_4partitioning_candidate_limit), + BLOCK_MAX_PARTITIONINGS); + config.tune_db_limit = astc::max(LERP(tune_db_limit_a_base) - 35 * ltexels, + LERP(tune_db_limit_b_base) - 19 * ltexels); + + config.tune_mse_overshoot = LERP(tune_mse_overshoot); + + config.tune_2_partition_early_out_limit_factor = LERP(tune_2_partition_early_out_limit_factor); + config.tune_3_partition_early_out_limit_factor = LERP(tune_3_partition_early_out_limit_factor); + config.tune_2_plane_early_out_limit_correlation = LERP(tune_2_plane_early_out_limit_correlation); + #undef LERP + #undef LERPI + #undef LERPUI + } + + // Set heuristics to the defaults for each color profile + config.cw_r_weight = 1.0f; + config.cw_g_weight = 1.0f; + config.cw_b_weight = 1.0f; + config.cw_a_weight = 1.0f; + + config.a_scale_radius = 0; + + config.rgbm_m_scale = 0.0f; + + config.profile = profile; + + // Values in this enum are from an external user, so not guaranteed to be + // bounded to the enum values + switch (static_cast<int>(profile)) + { + case ASTCENC_PRF_LDR: + case ASTCENC_PRF_LDR_SRGB: + break; + case ASTCENC_PRF_HDR_RGB_LDR_A: + case ASTCENC_PRF_HDR: + config.tune_db_limit = 999.0f; + break; + default: + return ASTCENC_ERR_BAD_PROFILE; + } + + // Flags field must not contain any unknown flag bits + status = validate_flags(flags); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + if (flags & ASTCENC_FLG_MAP_NORMAL) + { + // Normal map encoding uses L+A blocks, so allow one more partitioning + // than normal. We need need fewer bits for endpoints, so more likely + // to be able to use more partitions than an RGB/RGBA block + config.tune_partition_count_limit = astc::min(config.tune_partition_count_limit + 1u, 4u); + + config.cw_g_weight = 0.0f; + config.cw_b_weight = 0.0f; + config.tune_2_partition_early_out_limit_factor *= 1.5f; + config.tune_3_partition_early_out_limit_factor *= 1.5f; + config.tune_2_plane_early_out_limit_correlation = 0.99f; + + // Normals are prone to blocking artifacts on smooth curves + // so force compressor to try harder here ... + config.tune_db_limit *= 1.03f; + } + else if (flags & ASTCENC_FLG_MAP_RGBM) + { + config.rgbm_m_scale = 5.0f; + config.cw_a_weight = 2.0f * config.rgbm_m_scale; + } + else // (This is color data) + { + // This is a very basic perceptual metric for RGB color data, which weights error + // significance by the perceptual luminance contribution of each color channel. For + // luminance the usual weights to compute luminance from a linear RGB value are as + // follows: + // + // l = r * 0.3 + g * 0.59 + b * 0.11 + // + // ... but we scale these up to keep a better balance between color and alpha. Note + // that if the content is using alpha we'd recommend using the -a option to weight + // the color contribution by the alpha transparency. + if (flags & ASTCENC_FLG_USE_PERCEPTUAL) + { + config.cw_r_weight = 0.30f * 2.25f; + config.cw_g_weight = 0.59f * 2.25f; + config.cw_b_weight = 0.11f * 2.25f; + } + } + config.flags = flags; + + return ASTCENC_SUCCESS; +} + +/* See header for documentation. */ +astcenc_error astcenc_context_alloc( + const astcenc_config* configp, + unsigned int thread_count, + astcenc_context** context +) { + astcenc_error status; + const astcenc_config& config = *configp; + + status = validate_cpu_isa(); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + status = validate_cpu_float(); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + if (thread_count == 0) + { + return ASTCENC_ERR_BAD_PARAM; + } + +#if defined(ASTCENC_DIAGNOSTICS) + // Force single threaded compressor use in diagnostic mode. + if (thread_count != 1) + { + return ASTCENC_ERR_BAD_PARAM; + } +#endif + + astcenc_context* ctxo = new astcenc_context; + astcenc_contexti* ctx = &ctxo->context; + ctx->thread_count = thread_count; + ctx->config = config; + ctx->working_buffers = nullptr; + + // These are allocated per-compress, as they depend on image size + ctx->input_alpha_averages = nullptr; + + // Copy the config first and validate the copy (we may modify it) + status = validate_config(ctx->config); + if (status != ASTCENC_SUCCESS) + { + delete ctxo; + return status; + } + + ctx->bsd = aligned_malloc<block_size_descriptor>(sizeof(block_size_descriptor), ASTCENC_VECALIGN); + bool can_omit_modes = static_cast<bool>(config.flags & ASTCENC_FLG_SELF_DECOMPRESS_ONLY); + init_block_size_descriptor(config.block_x, config.block_y, config.block_z, + can_omit_modes, + config.tune_partition_count_limit, + static_cast<float>(config.tune_block_mode_limit) / 100.0f, + *ctx->bsd); + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + // Do setup only needed by compression + if (!(status & ASTCENC_FLG_DECOMPRESS_ONLY)) + { + // Turn a dB limit into a per-texel error for faster use later + if ((ctx->config.profile == ASTCENC_PRF_LDR) || (ctx->config.profile == ASTCENC_PRF_LDR_SRGB)) + { + ctx->config.tune_db_limit = astc::pow(0.1f, ctx->config.tune_db_limit * 0.1f) * 65535.0f * 65535.0f; + } + else + { + ctx->config.tune_db_limit = 0.0f; + } + + size_t worksize = sizeof(compression_working_buffers) * thread_count; + ctx->working_buffers = aligned_malloc<compression_working_buffers>(worksize, ASTCENC_VECALIGN); + static_assert((sizeof(compression_working_buffers) % ASTCENC_VECALIGN) == 0, + "compression_working_buffers size must be multiple of vector alignment"); + if (!ctx->working_buffers) + { + aligned_free<block_size_descriptor>(ctx->bsd); + delete ctxo; + *context = nullptr; + return ASTCENC_ERR_OUT_OF_MEM; + } + } +#endif + +#if defined(ASTCENC_DIAGNOSTICS) + ctx->trace_log = new TraceLog(ctx->config.trace_file_path); + if (!ctx->trace_log->m_file) + { + return ASTCENC_ERR_DTRACE_FAILURE; + } + + trace_add_data("block_x", config.block_x); + trace_add_data("block_y", config.block_y); + trace_add_data("block_z", config.block_z); +#endif + + *context = ctxo; + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + prepare_angular_tables(); +#endif + + return ASTCENC_SUCCESS; +} + +/* See header dor documentation. */ +void astcenc_context_free( + astcenc_context* ctxo +) { + if (ctxo) + { + astcenc_contexti* ctx = &ctxo->context; + aligned_free<compression_working_buffers>(ctx->working_buffers); + aligned_free<block_size_descriptor>(ctx->bsd); +#if defined(ASTCENC_DIAGNOSTICS) + delete ctx->trace_log; +#endif + delete ctxo; + } +} + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Compress an image, after any preflight has completed. + * + * @param[out] ctxo The compressor context. + * @param thread_index The thread index. + * @param image The intput image. + * @param swizzle The input swizzle. + * @param[out] buffer The output array for the compressed data. + */ +static void compress_image( + astcenc_context& ctxo, + unsigned int thread_index, + const astcenc_image& image, + const astcenc_swizzle& swizzle, + uint8_t* buffer +) { + astcenc_contexti& ctx = ctxo.context; + const block_size_descriptor& bsd = *ctx.bsd; + astcenc_profile decode_mode = ctx.config.profile; + + image_block blk; + + int block_x = bsd.xdim; + int block_y = bsd.ydim; + int block_z = bsd.zdim; + blk.texel_count = static_cast<uint8_t>(block_x * block_y * block_z); + + int dim_x = image.dim_x; + int dim_y = image.dim_y; + int dim_z = image.dim_z; + + int xblocks = (dim_x + block_x - 1) / block_x; + int yblocks = (dim_y + block_y - 1) / block_y; + int zblocks = (dim_z + block_z - 1) / block_z; + int block_count = zblocks * yblocks * xblocks; + + int row_blocks = xblocks; + int plane_blocks = xblocks * yblocks; + + // Populate the block channel weights + blk.channel_weight = vfloat4(ctx.config.cw_r_weight, + ctx.config.cw_g_weight, + ctx.config.cw_b_weight, + ctx.config.cw_a_weight); + + // Use preallocated scratch buffer + auto& temp_buffers = ctx.working_buffers[thread_index]; + + // Only the first thread actually runs the initializer + ctxo.manage_compress.init(block_count); + + // Determine if we can use an optimized load function + bool needs_swz = (swizzle.r != ASTCENC_SWZ_R) || (swizzle.g != ASTCENC_SWZ_G) || + (swizzle.b != ASTCENC_SWZ_B) || (swizzle.a != ASTCENC_SWZ_A); + + bool needs_hdr = (decode_mode == ASTCENC_PRF_HDR) || + (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A); + + bool use_fast_load = !needs_swz && !needs_hdr && + block_z == 1 && image.data_type == ASTCENC_TYPE_U8; + + auto load_func = load_image_block; + if (use_fast_load) + { + load_func = load_image_block_fast_ldr; + } + + // All threads run this processing loop until there is no work remaining + while (true) + { + unsigned int count; + unsigned int base = ctxo.manage_compress.get_task_assignment(16, count); + if (!count) + { + break; + } + + for (unsigned int i = base; i < base + count; i++) + { + // Decode i into x, y, z block indices + int z = i / plane_blocks; + unsigned int rem = i - (z * plane_blocks); + int y = rem / row_blocks; + int x = rem - (y * row_blocks); + + // Test if we can apply some basic alpha-scale RDO + bool use_full_block = true; + if (ctx.config.a_scale_radius != 0 && block_z == 1) + { + int start_x = x * block_x; + int end_x = astc::min(dim_x, start_x + block_x); + + int start_y = y * block_y; + int end_y = astc::min(dim_y, start_y + block_y); + + // SATs accumulate error, so don't test exactly zero. Test for + // less than 1 alpha in the expanded block footprint that + // includes the alpha radius. + int x_footprint = block_x + 2 * (ctx.config.a_scale_radius - 1); + + int y_footprint = block_y + 2 * (ctx.config.a_scale_radius - 1); + + float footprint = static_cast<float>(x_footprint * y_footprint); + float threshold = 0.9f / (255.0f * footprint); + + // Do we have any alpha values? + use_full_block = false; + for (int ay = start_y; ay < end_y; ay++) + { + for (int ax = start_x; ax < end_x; ax++) + { + float a_avg = ctx.input_alpha_averages[ay * dim_x + ax]; + if (a_avg > threshold) + { + use_full_block = true; + ax = end_x; + ay = end_y; + } + } + } + } + + // Fetch the full block for compression + if (use_full_block) + { + load_func(decode_mode, image, blk, bsd, x * block_x, y * block_y, z * block_z, swizzle); + + // Scale RGB error contribution by the maximum alpha in the block + // This encourages preserving alpha accuracy in regions with high + // transparency, and can buy up to 0.5 dB PSNR. + if (ctx.config.flags & ASTCENC_FLG_USE_ALPHA_WEIGHT) + { + float alpha_scale = blk.data_max.lane<3>() * (1.0f / 65535.0f); + blk.channel_weight = vfloat4(ctx.config.cw_r_weight * alpha_scale, + ctx.config.cw_g_weight * alpha_scale, + ctx.config.cw_b_weight * alpha_scale, + ctx.config.cw_a_weight); + } + } + // Apply alpha scale RDO - substitute constant color block + else + { + blk.origin_texel = vfloat4::zero(); + blk.data_min = vfloat4::zero(); + blk.data_mean = vfloat4::zero(); + blk.data_max = vfloat4::zero(); + blk.grayscale = true; + } + + int offset = ((z * yblocks + y) * xblocks + x) * 16; + uint8_t *bp = buffer + offset; + physical_compressed_block* pcb = reinterpret_cast<physical_compressed_block*>(bp); + compress_block(ctx, blk, *pcb, temp_buffers); + } + + ctxo.manage_compress.complete_task_assignment(count); + } +} + +/** + * @brief Compute regional averages in an image. + * + * This function can be called by multiple threads, but only after a single + * thread calls the setup function @c init_compute_averages(). + * + * Results are written back into @c img->input_alpha_averages. + * + * @param[out] ctx The context. + * @param ag The average and variance arguments created during setup. + */ +static void compute_averages( + astcenc_context& ctx, + const avg_args &ag +) { + pixel_region_args arg = ag.arg; + arg.work_memory = new vfloat4[ag.work_memory_size]; + + int size_x = ag.img_size_x; + int size_y = ag.img_size_y; + int size_z = ag.img_size_z; + + int step_xy = ag.blk_size_xy; + int step_z = ag.blk_size_z; + + int y_tasks = (size_y + step_xy - 1) / step_xy; + + // All threads run this processing loop until there is no work remaining + while (true) + { + unsigned int count; + unsigned int base = ctx.manage_avg.get_task_assignment(16, count); + if (!count) + { + break; + } + + for (unsigned int i = base; i < base + count; i++) + { + int z = (i / (y_tasks)) * step_z; + int y = (i - (z * y_tasks)) * step_xy; + + arg.size_z = astc::min(step_z, size_z - z); + arg.offset_z = z; + + arg.size_y = astc::min(step_xy, size_y - y); + arg.offset_y = y; + + for (int x = 0; x < size_x; x += step_xy) + { + arg.size_x = astc::min(step_xy, size_x - x); + arg.offset_x = x; + compute_pixel_region_variance(ctx.context, arg); + } + } + + ctx.manage_avg.complete_task_assignment(count); + } + + delete[] arg.work_memory; +} + +#endif + +/* See header for documentation. */ +astcenc_error astcenc_compress_image( + astcenc_context* ctxo, + astcenc_image* imagep, + const astcenc_swizzle* swizzle, + uint8_t* data_out, + size_t data_len, + unsigned int thread_index +) { +#if defined(ASTCENC_DECOMPRESS_ONLY) + (void)ctxo; + (void)imagep; + (void)swizzle; + (void)data_out; + (void)data_len; + (void)thread_index; + return ASTCENC_ERR_BAD_CONTEXT; +#else + astcenc_contexti* ctx = &ctxo->context; + astcenc_error status; + astcenc_image& image = *imagep; + + if (ctx->config.flags & ASTCENC_FLG_DECOMPRESS_ONLY) + { + return ASTCENC_ERR_BAD_CONTEXT; + } + + status = validate_compression_swizzle(*swizzle); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + if (thread_index >= ctx->thread_count) + { + return ASTCENC_ERR_BAD_PARAM; + } + + unsigned int block_x = ctx->config.block_x; + unsigned int block_y = ctx->config.block_y; + unsigned int block_z = ctx->config.block_z; + + unsigned int xblocks = (image.dim_x + block_x - 1) / block_x; + unsigned int yblocks = (image.dim_y + block_y - 1) / block_y; + unsigned int zblocks = (image.dim_z + block_z - 1) / block_z; + + // Check we have enough output space (16 bytes per block) + size_t size_needed = xblocks * yblocks * zblocks * 16; + if (data_len < size_needed) + { + return ASTCENC_ERR_OUT_OF_MEM; + } + + // If context thread count is one then implicitly reset + if (ctx->thread_count == 1) + { + astcenc_compress_reset(ctxo); + } + + if (ctx->config.a_scale_radius != 0) + { + // First thread to enter will do setup, other threads will subsequently + // enter the critical section but simply skip over the initialization + auto init_avg = [ctx, &image, swizzle]() { + // Perform memory allocations for the destination buffers + size_t texel_count = image.dim_x * image.dim_y * image.dim_z; + ctx->input_alpha_averages = new float[texel_count]; + + return init_compute_averages( + image, ctx->config.a_scale_radius, *swizzle, + ctx->avg_preprocess_args); + }; + + // Only the first thread actually runs the initializer + ctxo->manage_avg.init(init_avg); + + // All threads will enter this function and dynamically grab work + compute_averages(*ctxo, ctx->avg_preprocess_args); + } + + // Wait for compute_averages to complete before compressing + ctxo->manage_avg.wait(); + + compress_image(*ctxo, thread_index, image, *swizzle, data_out); + + // Wait for compress to complete before freeing memory + ctxo->manage_compress.wait(); + + auto term_compress = [ctx]() { + delete[] ctx->input_alpha_averages; + ctx->input_alpha_averages = nullptr; + }; + + // Only the first thread to arrive actually runs the term + ctxo->manage_compress.term(term_compress); + + return ASTCENC_SUCCESS; +#endif +} + +/* See header for documentation. */ +astcenc_error astcenc_compress_reset( + astcenc_context* ctxo +) { +#if defined(ASTCENC_DECOMPRESS_ONLY) + (void)ctxo; + return ASTCENC_ERR_BAD_CONTEXT; +#else + astcenc_contexti* ctx = &ctxo->context; + if (ctx->config.flags & ASTCENC_FLG_DECOMPRESS_ONLY) + { + return ASTCENC_ERR_BAD_CONTEXT; + } + + ctxo->manage_avg.reset(); + ctxo->manage_compress.reset(); + return ASTCENC_SUCCESS; +#endif +} + +/* See header for documentation. */ +astcenc_error astcenc_decompress_image( + astcenc_context* ctxo, + const uint8_t* data, + size_t data_len, + astcenc_image* image_outp, + const astcenc_swizzle* swizzle, + unsigned int thread_index +) { + astcenc_error status; + astcenc_image& image_out = *image_outp; + astcenc_contexti* ctx = &ctxo->context; + + // Today this doesn't matter (working set on stack) but might in future ... + if (thread_index >= ctx->thread_count) + { + return ASTCENC_ERR_BAD_PARAM; + } + + status = validate_decompression_swizzle(*swizzle); + if (status != ASTCENC_SUCCESS) + { + return status; + } + + unsigned int block_x = ctx->config.block_x; + unsigned int block_y = ctx->config.block_y; + unsigned int block_z = ctx->config.block_z; + + unsigned int xblocks = (image_out.dim_x + block_x - 1) / block_x; + unsigned int yblocks = (image_out.dim_y + block_y - 1) / block_y; + unsigned int zblocks = (image_out.dim_z + block_z - 1) / block_z; + + int row_blocks = xblocks; + int plane_blocks = xblocks * yblocks; + + // Check we have enough output space (16 bytes per block) + size_t size_needed = xblocks * yblocks * zblocks * 16; + if (data_len < size_needed) + { + return ASTCENC_ERR_OUT_OF_MEM; + } + + image_block blk; + blk.texel_count = static_cast<uint8_t>(block_x * block_y * block_z); + + // If context thread count is one then implicitly reset + if (ctx->thread_count == 1) + { + astcenc_decompress_reset(ctxo); + } + + // Only the first thread actually runs the initializer + ctxo->manage_decompress.init(zblocks * yblocks * xblocks); + + // All threads run this processing loop until there is no work remaining + while (true) + { + unsigned int count; + unsigned int base = ctxo->manage_decompress.get_task_assignment(128, count); + if (!count) + { + break; + } + + for (unsigned int i = base; i < base + count; i++) + { + // Decode i into x, y, z block indices + int z = i / plane_blocks; + unsigned int rem = i - (z * plane_blocks); + int y = rem / row_blocks; + int x = rem - (y * row_blocks); + + unsigned int offset = (((z * yblocks + y) * xblocks) + x) * 16; + const uint8_t* bp = data + offset; + + const physical_compressed_block& pcb = *reinterpret_cast<const physical_compressed_block*>(bp); + symbolic_compressed_block scb; + + physical_to_symbolic(*ctx->bsd, pcb, scb); + + decompress_symbolic_block(ctx->config.profile, *ctx->bsd, + x * block_x, y * block_y, z * block_z, + scb, blk); + + store_image_block(image_out, blk, *ctx->bsd, + x * block_x, y * block_y, z * block_z, *swizzle); + } + + ctxo->manage_decompress.complete_task_assignment(count); + } + + return ASTCENC_SUCCESS; +} + +/* See header for documentation. */ +astcenc_error astcenc_decompress_reset( + astcenc_context* ctxo +) { + ctxo->manage_decompress.reset(); + return ASTCENC_SUCCESS; +} + +/* See header for documentation. */ +astcenc_error astcenc_get_block_info( + astcenc_context* ctxo, + const uint8_t data[16], + astcenc_block_info* info +) { +#if defined(ASTCENC_DECOMPRESS_ONLY) + (void)ctxo; + (void)data; + (void)info; + return ASTCENC_ERR_BAD_CONTEXT; +#else + astcenc_contexti* ctx = &ctxo->context; + + // Decode the compressed data into a symbolic form + const physical_compressed_block&pcb = *reinterpret_cast<const physical_compressed_block*>(data); + symbolic_compressed_block scb; + physical_to_symbolic(*ctx->bsd, pcb, scb); + + // Fetch the appropriate partition and decimation tables + block_size_descriptor& bsd = *ctx->bsd; + + // Start from a clean slate + memset(info, 0, sizeof(*info)); + + // Basic info we can always populate + info->profile = ctx->config.profile; + + info->block_x = ctx->config.block_x; + info->block_y = ctx->config.block_y; + info->block_z = ctx->config.block_z; + info->texel_count = bsd.texel_count; + + // Check for error blocks first + info->is_error_block = scb.block_type == SYM_BTYPE_ERROR; + if (info->is_error_block) + { + return ASTCENC_SUCCESS; + } + + // Check for constant color blocks second + info->is_constant_block = scb.block_type == SYM_BTYPE_CONST_F16 || + scb.block_type == SYM_BTYPE_CONST_U16; + if (info->is_constant_block) + { + return ASTCENC_SUCCESS; + } + + // Otherwise handle a full block ; known to be valid after conditions above have been checked + int partition_count = scb.partition_count; + const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index); + + const block_mode& bm = bsd.get_block_mode(scb.block_mode); + const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode); + + info->weight_x = di.weight_x; + info->weight_y = di.weight_y; + info->weight_z = di.weight_z; + + info->is_dual_plane_block = bm.is_dual_plane != 0; + + info->partition_count = scb.partition_count; + info->partition_index = scb.partition_index; + info->dual_plane_component = scb.plane2_component; + + info->color_level_count = get_quant_level(scb.get_color_quant_mode()); + info->weight_level_count = get_quant_level(bm.get_weight_quant_mode()); + + // Unpack color endpoints for each active partition + for (unsigned int i = 0; i < scb.partition_count; i++) + { + bool rgb_hdr; + bool a_hdr; + vint4 endpnt[2]; + + unpack_color_endpoints(ctx->config.profile, + scb.color_formats[i], + scb.color_values[i], + rgb_hdr, a_hdr, + endpnt[0], endpnt[1]); + + // Store the color endpoint mode info + info->color_endpoint_modes[i] = scb.color_formats[i]; + info->is_hdr_block = info->is_hdr_block || rgb_hdr || a_hdr; + + // Store the unpacked and decoded color endpoint + vmask4 hdr_mask(rgb_hdr, rgb_hdr, rgb_hdr, a_hdr); + for (int j = 0; j < 2; j++) + { + vint4 color_lns = lns_to_sf16(endpnt[j]); + vint4 color_unorm = unorm16_to_sf16(endpnt[j]); + vint4 datai = select(color_unorm, color_lns, hdr_mask); + store(float16_to_float(datai), info->color_endpoints[i][j]); + } + } + + // Unpack weights for each texel + int weight_plane1[BLOCK_MAX_TEXELS]; + int weight_plane2[BLOCK_MAX_TEXELS]; + + unpack_weights(bsd, scb, di, bm.is_dual_plane, weight_plane1, weight_plane2); + for (unsigned int i = 0; i < bsd.texel_count; i++) + { + info->weight_values_plane1[i] = static_cast<float>(weight_plane1[i]) * (1.0f / WEIGHTS_TEXEL_SUM); + if (info->is_dual_plane_block) + { + info->weight_values_plane2[i] = static_cast<float>(weight_plane2[i]) * (1.0f / WEIGHTS_TEXEL_SUM); + } + } + + // Unpack partition assignments for each texel + for (unsigned int i = 0; i < bsd.texel_count; i++) + { + info->partition_assignment[i] = pi.partition_of_texel[i]; + } + + return ASTCENC_SUCCESS; +#endif +} + +/* See header for documentation. */ +const char* astcenc_get_error_string( + astcenc_error status +) { + // Values in this enum are from an external user, so not guaranteed to be + // bounded to the enum values + switch (static_cast<int>(status)) + { + case ASTCENC_SUCCESS: + return "ASTCENC_SUCCESS"; + case ASTCENC_ERR_OUT_OF_MEM: + return "ASTCENC_ERR_OUT_OF_MEM"; + case ASTCENC_ERR_BAD_CPU_FLOAT: + return "ASTCENC_ERR_BAD_CPU_FLOAT"; + case ASTCENC_ERR_BAD_CPU_ISA: + return "ASTCENC_ERR_BAD_CPU_ISA"; + case ASTCENC_ERR_BAD_PARAM: + return "ASTCENC_ERR_BAD_PARAM"; + case ASTCENC_ERR_BAD_BLOCK_SIZE: + return "ASTCENC_ERR_BAD_BLOCK_SIZE"; + case ASTCENC_ERR_BAD_PROFILE: + return "ASTCENC_ERR_BAD_PROFILE"; + case ASTCENC_ERR_BAD_QUALITY: + return "ASTCENC_ERR_BAD_QUALITY"; + case ASTCENC_ERR_BAD_FLAGS: + return "ASTCENC_ERR_BAD_FLAGS"; + case ASTCENC_ERR_BAD_SWIZZLE: + return "ASTCENC_ERR_BAD_SWIZZLE"; + case ASTCENC_ERR_BAD_CONTEXT: + return "ASTCENC_ERR_BAD_CONTEXT"; + case ASTCENC_ERR_NOT_IMPLEMENTED: + return "ASTCENC_ERR_NOT_IMPLEMENTED"; +#if defined(ASTCENC_DIAGNOSTICS) + case ASTCENC_ERR_DTRACE_FAILURE: + return "ASTCENC_ERR_DTRACE_FAILURE"; +#endif + default: + return nullptr; + } +} diff --git a/thirdparty/astcenc/astcenc_find_best_partitioning.cpp b/thirdparty/astcenc/astcenc_find_best_partitioning.cpp new file mode 100644 index 0000000000..ffde3c7060 --- /dev/null +++ b/thirdparty/astcenc/astcenc_find_best_partitioning.cpp @@ -0,0 +1,780 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions for finding best partition for a block. + * + * The partition search operates in two stages. The first pass uses kmeans clustering to group + * texels into an ideal partitioning for the requested partition count, and then compares that + * against the 1024 partitionings generated by the ASTC partition hash function. The generated + * partitions are then ranked by the number of texels in the wrong partition, compared to the ideal + * clustering. All 1024 partitions are tested for similarity and ranked, apart from duplicates and + * partitionings that actually generate fewer than the requested partition count, but only the top + * N candidates are actually put through a more detailed search. N is determined by the compressor + * quality preset. + * + * For the detailed search, each candidate is checked against two possible encoding methods: + * + * - The best partitioning assuming different chroma colors (RGB + RGB or RGB + delta endpoints). + * - The best partitioning assuming same chroma colors (RGB + scale endpoints). + * + * This is implemented by computing the compute mean color and dominant direction for each + * partition. This defines two lines, both of which go through the mean color value. + * + * - One line has a direction defined by the dominant direction; this is used to assess the error + * from using an uncorrelated color representation. + * - The other line goes through (0,0,0,1) and is used to assess the error from using a same chroma + * (RGB + scale) color representation. + * + * The best candidate is selected by computing the squared-errors that result from using these + * lines for endpoint selection. + */ + +#include <limits> +#include "astcenc_internal.h" + +/** + * @brief Pick some initial kmeans cluster centers. + * + * @param blk The image block color data to compress. + * @param texel_count The number of texels in the block. + * @param partition_count The number of partitions in the block. + * @param[out] cluster_centers The initial partition cluster center colors. + */ +static void kmeans_init( + const image_block& blk, + unsigned int texel_count, + unsigned int partition_count, + vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS] +) { + promise(texel_count > 0); + promise(partition_count > 0); + + unsigned int clusters_selected = 0; + float distances[BLOCK_MAX_TEXELS]; + + // Pick a random sample as first cluster center; 145897 from random.org + unsigned int sample = 145897 % texel_count; + vfloat4 center_color = blk.texel(sample); + cluster_centers[clusters_selected] = center_color; + clusters_selected++; + + // Compute the distance to the first cluster center + float distance_sum = 0.0f; + for (unsigned int i = 0; i < texel_count; i++) + { + vfloat4 color = blk.texel(i); + vfloat4 diff = color - center_color; + float distance = dot_s(diff * diff, blk.channel_weight); + distance_sum += distance; + distances[i] = distance; + } + + // More numbers from random.org for weighted-random center selection + const float cluster_cutoffs[9] { + 0.626220f, 0.932770f, 0.275454f, + 0.318558f, 0.240113f, 0.009190f, + 0.347661f, 0.731960f, 0.156391f + }; + + unsigned int cutoff = (clusters_selected - 1) + 3 * (partition_count - 2); + + // Pick the remaining samples as needed + while (true) + { + // Pick the next center in a weighted-random fashion. + float summa = 0.0f; + float distance_cutoff = distance_sum * cluster_cutoffs[cutoff++]; + for (sample = 0; sample < texel_count; sample++) + { + summa += distances[sample]; + if (summa >= distance_cutoff) + { + break; + } + } + + // Clamp to a valid range and store the selected cluster center + sample = astc::min(sample, texel_count - 1); + + center_color = blk.texel(sample); + cluster_centers[clusters_selected++] = center_color; + if (clusters_selected >= partition_count) + { + break; + } + + // Compute the distance to the new cluster center, keep the min dist + distance_sum = 0.0f; + for (unsigned int i = 0; i < texel_count; i++) + { + vfloat4 color = blk.texel(i); + vfloat4 diff = color - center_color; + float distance = dot_s(diff * diff, blk.channel_weight); + distance = astc::min(distance, distances[i]); + distance_sum += distance; + distances[i] = distance; + } + } +} + +/** + * @brief Assign texels to clusters, based on a set of chosen center points. + * + * @param blk The image block color data to compress. + * @param texel_count The number of texels in the block. + * @param partition_count The number of partitions in the block. + * @param cluster_centers The partition cluster center colors. + * @param[out] partition_of_texel The partition assigned for each texel. + */ +static void kmeans_assign( + const image_block& blk, + unsigned int texel_count, + unsigned int partition_count, + const vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS], + uint8_t partition_of_texel[BLOCK_MAX_TEXELS] +) { + promise(texel_count > 0); + promise(partition_count > 0); + + uint8_t partition_texel_count[BLOCK_MAX_PARTITIONS] { 0 }; + + // Find the best partition for every texel + for (unsigned int i = 0; i < texel_count; i++) + { + float best_distance = std::numeric_limits<float>::max(); + unsigned int best_partition = 0; + + vfloat4 color = blk.texel(i); + for (unsigned int j = 0; j < partition_count; j++) + { + vfloat4 diff = color - cluster_centers[j]; + float distance = dot_s(diff * diff, blk.channel_weight); + if (distance < best_distance) + { + best_distance = distance; + best_partition = j; + } + } + + partition_of_texel[i] = static_cast<uint8_t>(best_partition); + partition_texel_count[best_partition]++; + } + + // It is possible to get a situation where a partition ends up without any texels. In this case, + // assign texel N to partition N. This is silly, but ensures that every partition retains at + // least one texel. Reassigning a texel in this manner may cause another partition to go empty, + // so if we actually did a reassignment, run the whole loop over again. + bool problem_case; + do + { + problem_case = false; + for (unsigned int i = 0; i < partition_count; i++) + { + if (partition_texel_count[i] == 0) + { + partition_texel_count[partition_of_texel[i]]--; + partition_texel_count[i]++; + partition_of_texel[i] = static_cast<uint8_t>(i); + problem_case = true; + } + } + } while (problem_case); +} + +/** + * @brief Compute new cluster centers based on their center of gravity. + * + * @param blk The image block color data to compress. + * @param texel_count The number of texels in the block. + * @param partition_count The number of partitions in the block. + * @param[out] cluster_centers The new cluster center colors. + * @param partition_of_texel The partition assigned for each texel. + */ +static void kmeans_update( + const image_block& blk, + unsigned int texel_count, + unsigned int partition_count, + vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS], + const uint8_t partition_of_texel[BLOCK_MAX_TEXELS] +) { + promise(texel_count > 0); + promise(partition_count > 0); + + vfloat4 color_sum[BLOCK_MAX_PARTITIONS] { + vfloat4::zero(), + vfloat4::zero(), + vfloat4::zero(), + vfloat4::zero() + }; + + uint8_t partition_texel_count[BLOCK_MAX_PARTITIONS] { 0 }; + + // Find the center-of-gravity in each cluster + for (unsigned int i = 0; i < texel_count; i++) + { + uint8_t partition = partition_of_texel[i]; + color_sum[partition] += blk.texel(i); + partition_texel_count[partition]++; + } + + // Set the center of gravity to be the new cluster center + for (unsigned int i = 0; i < partition_count; i++) + { + float scale = 1.0f / static_cast<float>(partition_texel_count[i]); + cluster_centers[i] = color_sum[i] * scale; + } +} + +/** + * @brief Compute bit-mismatch for partitioning in 2-partition mode. + * + * @param a The texel assignment bitvector for the block. + * @param b The texel assignment bitvector for the partition table. + * + * @return The number of bit mismatches. + */ +static inline unsigned int partition_mismatch2( + const uint64_t a[2], + const uint64_t b[2] +) { + int v1 = popcount(a[0] ^ b[0]) + popcount(a[1] ^ b[1]); + int v2 = popcount(a[0] ^ b[1]) + popcount(a[1] ^ b[0]); + return astc::min(v1, v2); +} + +/** + * @brief Compute bit-mismatch for partitioning in 3-partition mode. + * + * @param a The texel assignment bitvector for the block. + * @param b The texel assignment bitvector for the partition table. + * + * @return The number of bit mismatches. + */ +static inline unsigned int partition_mismatch3( + const uint64_t a[3], + const uint64_t b[3] +) { + int p00 = popcount(a[0] ^ b[0]); + int p01 = popcount(a[0] ^ b[1]); + int p02 = popcount(a[0] ^ b[2]); + + int p10 = popcount(a[1] ^ b[0]); + int p11 = popcount(a[1] ^ b[1]); + int p12 = popcount(a[1] ^ b[2]); + + int p20 = popcount(a[2] ^ b[0]); + int p21 = popcount(a[2] ^ b[1]); + int p22 = popcount(a[2] ^ b[2]); + + int s0 = p11 + p22; + int s1 = p12 + p21; + int v0 = astc::min(s0, s1) + p00; + + int s2 = p10 + p22; + int s3 = p12 + p20; + int v1 = astc::min(s2, s3) + p01; + + int s4 = p10 + p21; + int s5 = p11 + p20; + int v2 = astc::min(s4, s5) + p02; + + return astc::min(v0, v1, v2); +} + +/** + * @brief Compute bit-mismatch for partitioning in 4-partition mode. + * + * @param a The texel assignment bitvector for the block. + * @param b The texel assignment bitvector for the partition table. + * + * @return The number of bit mismatches. + */ +static inline unsigned int partition_mismatch4( + const uint64_t a[4], + const uint64_t b[4] +) { + int p00 = popcount(a[0] ^ b[0]); + int p01 = popcount(a[0] ^ b[1]); + int p02 = popcount(a[0] ^ b[2]); + int p03 = popcount(a[0] ^ b[3]); + + int p10 = popcount(a[1] ^ b[0]); + int p11 = popcount(a[1] ^ b[1]); + int p12 = popcount(a[1] ^ b[2]); + int p13 = popcount(a[1] ^ b[3]); + + int p20 = popcount(a[2] ^ b[0]); + int p21 = popcount(a[2] ^ b[1]); + int p22 = popcount(a[2] ^ b[2]); + int p23 = popcount(a[2] ^ b[3]); + + int p30 = popcount(a[3] ^ b[0]); + int p31 = popcount(a[3] ^ b[1]); + int p32 = popcount(a[3] ^ b[2]); + int p33 = popcount(a[3] ^ b[3]); + + int mx23 = astc::min(p22 + p33, p23 + p32); + int mx13 = astc::min(p21 + p33, p23 + p31); + int mx12 = astc::min(p21 + p32, p22 + p31); + int mx03 = astc::min(p20 + p33, p23 + p30); + int mx02 = astc::min(p20 + p32, p22 + p30); + int mx01 = astc::min(p21 + p30, p20 + p31); + + int v0 = p00 + astc::min(p11 + mx23, p12 + mx13, p13 + mx12); + int v1 = p01 + astc::min(p10 + mx23, p12 + mx03, p13 + mx02); + int v2 = p02 + astc::min(p11 + mx03, p10 + mx13, p13 + mx01); + int v3 = p03 + astc::min(p11 + mx02, p12 + mx01, p10 + mx12); + + return astc::min(v0, v1, v2, v3); +} + +using mismatch_dispatch = unsigned int (*)(const uint64_t*, const uint64_t*); + +/** + * @brief Count the partition table mismatches vs the data clustering. + * + * @param bsd The block size information. + * @param partition_count The number of partitions in the block. + * @param bitmaps The block texel partition assignment patterns. + * @param[out] mismatch_counts The array storing per partitioning mismatch counts. + */ +static void count_partition_mismatch_bits( + const block_size_descriptor& bsd, + unsigned int partition_count, + const uint64_t bitmaps[BLOCK_MAX_PARTITIONS], + unsigned int mismatch_counts[BLOCK_MAX_PARTITIONINGS] +) { + unsigned int active_count = bsd.partitioning_count_selected[partition_count - 1]; + promise(active_count > 0); + + if (partition_count == 2) + { + for (unsigned int i = 0; i < active_count; i++) + { + mismatch_counts[i] = partition_mismatch2(bitmaps, bsd.coverage_bitmaps_2[i]); + } + } + else if (partition_count == 3) + { + for (unsigned int i = 0; i < active_count; i++) + { + mismatch_counts[i] = partition_mismatch3(bitmaps, bsd.coverage_bitmaps_3[i]); + } + } + else + { + for (unsigned int i = 0; i < active_count; i++) + { + mismatch_counts[i] = partition_mismatch4(bitmaps, bsd.coverage_bitmaps_4[i]); + } + } +} + +/** + * @brief Use counting sort on the mismatch array to sort partition candidates. + * + * @param partitioning_count The number of packed partitionings. + * @param mismatch_count Partitioning mismatch counts, in index order. + * @param[out] partition_ordering Partition index values, in mismatch order. + * + * @return The number of active partitions in this selection. + */ +static unsigned int get_partition_ordering_by_mismatch_bits( + unsigned int partitioning_count, + const unsigned int mismatch_count[BLOCK_MAX_PARTITIONINGS], + unsigned int partition_ordering[BLOCK_MAX_PARTITIONINGS] +) { + promise(partitioning_count > 0); + unsigned int mscount[256] { 0 }; + + // Create the histogram of mismatch counts + for (unsigned int i = 0; i < partitioning_count; i++) + { + mscount[mismatch_count[i]]++; + } + + unsigned int active_count = partitioning_count - mscount[255]; + + // Create a running sum from the histogram array + // Cells store previous values only; i.e. exclude self after sum + unsigned int summa = 0; + for (unsigned int i = 0; i < 256; i++) + { + unsigned int cnt = mscount[i]; + mscount[i] = summa; + summa += cnt; + } + + // Use the running sum as the index, incrementing after read to allow + // sequential entries with the same count + for (unsigned int i = 0; i < partitioning_count; i++) + { + unsigned int idx = mscount[mismatch_count[i]]++; + partition_ordering[idx] = i; + } + + return active_count; +} + +/** + * @brief Use k-means clustering to compute a partition ordering for a block.. + * + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param partition_count The desired number of partitions in the block. + * @param[out] partition_ordering The list of recommended partition indices, in priority order. + * + * @return The number of active partitionings in this selection. + */ +static unsigned int compute_kmeans_partition_ordering( + const block_size_descriptor& bsd, + const image_block& blk, + unsigned int partition_count, + unsigned int partition_ordering[BLOCK_MAX_PARTITIONINGS] +) { + vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS]; + uint8_t texel_partitions[BLOCK_MAX_TEXELS]; + + // Use three passes of k-means clustering to partition the block data + for (unsigned int i = 0; i < 3; i++) + { + if (i == 0) + { + kmeans_init(blk, bsd.texel_count, partition_count, cluster_centers); + } + else + { + kmeans_update(blk, bsd.texel_count, partition_count, cluster_centers, texel_partitions); + } + + kmeans_assign(blk, bsd.texel_count, partition_count, cluster_centers, texel_partitions); + } + + // Construct the block bitmaps of texel assignments to each partition + uint64_t bitmaps[BLOCK_MAX_PARTITIONS] { 0 }; + unsigned int texels_to_process = astc::min(bsd.texel_count, BLOCK_MAX_KMEANS_TEXELS); + promise(texels_to_process > 0); + for (unsigned int i = 0; i < texels_to_process; i++) + { + unsigned int idx = bsd.kmeans_texels[i]; + bitmaps[texel_partitions[idx]] |= 1ULL << i; + } + + // Count the mismatch between the block and the format's partition tables + unsigned int mismatch_counts[BLOCK_MAX_PARTITIONINGS]; + count_partition_mismatch_bits(bsd, partition_count, bitmaps, mismatch_counts); + + // Sort the partitions based on the number of mismatched bits + return get_partition_ordering_by_mismatch_bits( + bsd.partitioning_count_selected[partition_count - 1], + mismatch_counts, partition_ordering); +} + +/** + * @brief Insert a partitioning into an order list of results, sorted by error. + * + * @param max_values The max number of entries in the best result arrays. + * @param this_error The error of the new entry. + * @param this_partition The partition ID of the new entry. + * @param[out] best_errors The array of best error values. + * @param[out] best_partitions The array of best partition values. + */ +static void insert_result( + unsigned int max_values, + float this_error, + unsigned int this_partition, + float* best_errors, + unsigned int* best_partitions) +{ + promise(max_values > 0); + + // Don't bother searching if the current worst error beats the new error + if (this_error >= best_errors[max_values - 1]) + { + return; + } + + // Else insert into the list in error-order + for (unsigned int i = 0; i < max_values; i++) + { + // Existing result is better - move on ... + if (this_error > best_errors[i]) + { + continue; + } + + // Move existing results down one + for (unsigned int j = max_values - 1; j > i; j--) + { + best_errors[j] = best_errors[j - 1]; + best_partitions[j] = best_partitions[j - 1]; + } + + // Insert new result + best_errors[i] = this_error; + best_partitions[i] = this_partition; + break; + } +} + +/* See header for documentation. */ +unsigned int find_best_partition_candidates( + const block_size_descriptor& bsd, + const image_block& blk, + unsigned int partition_count, + unsigned int partition_search_limit, + unsigned int best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES], + unsigned int requested_candidates +) { + // Constant used to estimate quantization error for a given partitioning; the optimal value for + // this depends on bitrate. These values have been determined empirically. + unsigned int texels_per_block = bsd.texel_count; + float weight_imprecision_estim = 0.055f; + if (texels_per_block <= 20) + { + weight_imprecision_estim = 0.03f; + } + else if (texels_per_block <= 31) + { + weight_imprecision_estim = 0.04f; + } + else if (texels_per_block <= 41) + { + weight_imprecision_estim = 0.05f; + } + + promise(partition_count > 0); + promise(partition_search_limit > 0); + + weight_imprecision_estim = weight_imprecision_estim * weight_imprecision_estim; + + unsigned int partition_sequence[BLOCK_MAX_PARTITIONINGS]; + unsigned int sequence_len = compute_kmeans_partition_ordering(bsd, blk, partition_count, partition_sequence); + partition_search_limit = astc::min(partition_search_limit, sequence_len); + requested_candidates = astc::min(partition_search_limit, requested_candidates); + + bool uses_alpha = !blk.is_constant_channel(3); + + // Partitioning errors assuming uncorrelated-chrominance endpoints + float uncor_best_errors[TUNE_MAX_PARTITIONING_CANDIDATES]; + unsigned int uncor_best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES]; + + // Partitioning errors assuming same-chrominance endpoints + float samec_best_errors[TUNE_MAX_PARTITIONING_CANDIDATES]; + unsigned int samec_best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES]; + + for (unsigned int i = 0; i < requested_candidates; i++) + { + uncor_best_errors[i] = ERROR_CALC_DEFAULT; + samec_best_errors[i] = ERROR_CALC_DEFAULT; + } + + if (uses_alpha) + { + for (unsigned int i = 0; i < partition_search_limit; i++) + { + unsigned int partition = partition_sequence[i]; + const auto& pi = bsd.get_raw_partition_info(partition_count, partition); + + // Compute weighting to give to each component in each partition + partition_metrics pms[BLOCK_MAX_PARTITIONS]; + + compute_avgs_and_dirs_4_comp(pi, blk, pms); + + line4 uncor_lines[BLOCK_MAX_PARTITIONS]; + line4 samec_lines[BLOCK_MAX_PARTITIONS]; + + processed_line4 uncor_plines[BLOCK_MAX_PARTITIONS]; + processed_line4 samec_plines[BLOCK_MAX_PARTITIONS]; + + float uncor_line_lens[BLOCK_MAX_PARTITIONS]; + float samec_line_lens[BLOCK_MAX_PARTITIONS]; + + for (unsigned int j = 0; j < partition_count; j++) + { + partition_metrics& pm = pms[j]; + + uncor_lines[j].a = pm.avg; + uncor_lines[j].b = normalize_safe(pm.dir, unit4()); + + uncor_plines[j].amod = uncor_lines[j].a - uncor_lines[j].b * dot(uncor_lines[j].a, uncor_lines[j].b); + uncor_plines[j].bs = uncor_lines[j].b; + + samec_lines[j].a = vfloat4::zero(); + samec_lines[j].b = normalize_safe(pm.avg, unit4()); + + samec_plines[j].amod = vfloat4::zero(); + samec_plines[j].bs = samec_lines[j].b; + } + + float uncor_error = 0.0f; + float samec_error = 0.0f; + + compute_error_squared_rgba(pi, + blk, + uncor_plines, + samec_plines, + uncor_line_lens, + samec_line_lens, + uncor_error, + samec_error); + + // Compute an estimate of error introduced by weight quantization imprecision. + // This error is computed as follows, for each partition + // 1: compute the principal-axis vector (full length) in error-space + // 2: convert the principal-axis vector to regular RGB-space + // 3: scale the vector by a constant that estimates average quantization error + // 4: for each texel, square the vector, then do a dot-product with the texel's + // error weight; sum up the results across all texels. + // 4(optimized): square the vector once, then do a dot-product with the average + // texel error, then multiply by the number of texels. + + for (unsigned int j = 0; j < partition_count; j++) + { + float tpp = static_cast<float>(pi.partition_texel_count[j]); + vfloat4 error_weights(tpp * weight_imprecision_estim); + + vfloat4 uncor_vector = uncor_lines[j].b * uncor_line_lens[j]; + vfloat4 samec_vector = samec_lines[j].b * samec_line_lens[j]; + + uncor_error += dot_s(uncor_vector * uncor_vector, error_weights); + samec_error += dot_s(samec_vector * samec_vector, error_weights); + } + + insert_result(requested_candidates, uncor_error, partition, uncor_best_errors, uncor_best_partitions); + insert_result(requested_candidates, samec_error, partition, samec_best_errors, samec_best_partitions); + } + } + else + { + for (unsigned int i = 0; i < partition_search_limit; i++) + { + unsigned int partition = partition_sequence[i]; + const auto& pi = bsd.get_raw_partition_info(partition_count, partition); + + // Compute weighting to give to each component in each partition + partition_metrics pms[BLOCK_MAX_PARTITIONS]; + compute_avgs_and_dirs_3_comp_rgb(pi, blk, pms); + + partition_lines3 plines[BLOCK_MAX_PARTITIONS]; + + for (unsigned int j = 0; j < partition_count; j++) + { + partition_metrics& pm = pms[j]; + partition_lines3& pl = plines[j]; + + pl.uncor_line.a = pm.avg; + pl.uncor_line.b = normalize_safe(pm.dir, unit3()); + + pl.samec_line.a = vfloat4::zero(); + pl.samec_line.b = normalize_safe(pm.avg, unit3()); + + pl.uncor_pline.amod = pl.uncor_line.a - pl.uncor_line.b * dot3(pl.uncor_line.a, pl.uncor_line.b); + pl.uncor_pline.bs = pl.uncor_line.b; + + pl.samec_pline.amod = vfloat4::zero(); + pl.samec_pline.bs = pl.samec_line.b; + } + + float uncor_error = 0.0f; + float samec_error = 0.0f; + + compute_error_squared_rgb(pi, + blk, + plines, + uncor_error, + samec_error); + + // Compute an estimate of error introduced by weight quantization imprecision. + // This error is computed as follows, for each partition + // 1: compute the principal-axis vector (full length) in error-space + // 2: convert the principal-axis vector to regular RGB-space + // 3: scale the vector by a constant that estimates average quantization error + // 4: for each texel, square the vector, then do a dot-product with the texel's + // error weight; sum up the results across all texels. + // 4(optimized): square the vector once, then do a dot-product with the average + // texel error, then multiply by the number of texels. + + for (unsigned int j = 0; j < partition_count; j++) + { + partition_lines3& pl = plines[j]; + + float tpp = static_cast<float>(pi.partition_texel_count[j]); + vfloat4 error_weights(tpp * weight_imprecision_estim); + + vfloat4 uncor_vector = pl.uncor_line.b * pl.uncor_line_len; + vfloat4 samec_vector = pl.samec_line.b * pl.samec_line_len; + + uncor_error += dot3_s(uncor_vector * uncor_vector, error_weights); + samec_error += dot3_s(samec_vector * samec_vector, error_weights); + } + + insert_result(requested_candidates, uncor_error, partition, uncor_best_errors, uncor_best_partitions); + insert_result(requested_candidates, samec_error, partition, samec_best_errors, samec_best_partitions); + } + } + + bool best_is_uncor = uncor_best_partitions[0] > samec_best_partitions[0]; + + unsigned int interleave[2 * TUNE_MAX_PARTITIONING_CANDIDATES]; + for (unsigned int i = 0; i < requested_candidates; i++) + { + if (best_is_uncor) + { + interleave[2 * i] = bsd.get_raw_partition_info(partition_count, uncor_best_partitions[i]).partition_index; + interleave[2 * i + 1] = bsd.get_raw_partition_info(partition_count, samec_best_partitions[i]).partition_index; + } + else + { + interleave[2 * i] = bsd.get_raw_partition_info(partition_count, samec_best_partitions[i]).partition_index; + interleave[2 * i + 1] = bsd.get_raw_partition_info(partition_count, uncor_best_partitions[i]).partition_index; + } + } + + uint64_t bitmasks[1024/64] { 0 }; + unsigned int emitted = 0; + + // Deduplicate the first "requested" entries + for (unsigned int i = 0; i < requested_candidates * 2; i++) + { + unsigned int partition = interleave[i]; + + unsigned int word = partition / 64; + unsigned int bit = partition % 64; + + bool written = bitmasks[word] & (1ull << bit); + + if (!written) + { + best_partitions[emitted] = partition; + bitmasks[word] |= 1ull << bit; + emitted++; + + if (emitted == requested_candidates) + { + break; + } + } + } + + return emitted; +} + +#endif diff --git a/thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp b/thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp new file mode 100644 index 0000000000..5145e08693 --- /dev/null +++ b/thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp @@ -0,0 +1,1663 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions for computing color endpoints and texel weights. + */ + +#include <cassert> + +#include "astcenc_internal.h" +#include "astcenc_vecmathlib.h" + +/** + * @brief Compute the infilled weight for N texel indices in a decimated grid. + * + * @param di The weight grid decimation to use. + * @param weights The decimated weight values to use. + * @param index The first texel index to interpolate. + * + * @return The interpolated weight for the given set of SIMD_WIDTH texels. + */ +static vfloat bilinear_infill_vla( + const decimation_info& di, + const float* weights, + unsigned int index +) { + // Load the bilinear filter texel weight indexes in the decimated grid + vint weight_idx0 = vint(di.texel_weights_tr[0] + index); + vint weight_idx1 = vint(di.texel_weights_tr[1] + index); + vint weight_idx2 = vint(di.texel_weights_tr[2] + index); + vint weight_idx3 = vint(di.texel_weights_tr[3] + index); + + // Load the bilinear filter weights from the decimated grid + vfloat weight_val0 = gatherf(weights, weight_idx0); + vfloat weight_val1 = gatherf(weights, weight_idx1); + vfloat weight_val2 = gatherf(weights, weight_idx2); + vfloat weight_val3 = gatherf(weights, weight_idx3); + + // Load the weight contribution factors for each decimated weight + vfloat tex_weight_float0 = loada(di.texel_weight_contribs_float_tr[0] + index); + vfloat tex_weight_float1 = loada(di.texel_weight_contribs_float_tr[1] + index); + vfloat tex_weight_float2 = loada(di.texel_weight_contribs_float_tr[2] + index); + vfloat tex_weight_float3 = loada(di.texel_weight_contribs_float_tr[3] + index); + + // Compute the bilinear interpolation to generate the per-texel weight + return (weight_val0 * tex_weight_float0 + weight_val1 * tex_weight_float1) + + (weight_val2 * tex_weight_float2 + weight_val3 * tex_weight_float3); +} + +/** + * @brief Compute the infilled weight for N texel indices in a decimated grid. + * + * This is specialized version which computes only two weights per texel for + * encodings that are only decimated in a single axis. + * + * @param di The weight grid decimation to use. + * @param weights The decimated weight values to use. + * @param index The first texel index to interpolate. + * + * @return The interpolated weight for the given set of SIMD_WIDTH texels. + */ +static vfloat bilinear_infill_vla_2( + const decimation_info& di, + const float* weights, + unsigned int index +) { + // Load the bilinear filter texel weight indexes in the decimated grid + vint weight_idx0 = vint(di.texel_weights_tr[0] + index); + vint weight_idx1 = vint(di.texel_weights_tr[1] + index); + + // Load the bilinear filter weights from the decimated grid + vfloat weight_val0 = gatherf(weights, weight_idx0); + vfloat weight_val1 = gatherf(weights, weight_idx1); + + // Load the weight contribution factors for each decimated weight + vfloat tex_weight_float0 = loada(di.texel_weight_contribs_float_tr[0] + index); + vfloat tex_weight_float1 = loada(di.texel_weight_contribs_float_tr[1] + index); + + // Compute the bilinear interpolation to generate the per-texel weight + return (weight_val0 * tex_weight_float0 + weight_val1 * tex_weight_float1); +} + +/** + * @brief Compute the ideal endpoints and weights for 1 color component. + * + * @param blk The image block color data to compress. + * @param pi The partition info for the current trial. + * @param[out] ei The computed ideal endpoints and weights. + * @param component The color component to compute. + */ +static void compute_ideal_colors_and_weights_1_comp( + const image_block& blk, + const partition_info& pi, + endpoints_and_weights& ei, + unsigned int component +) { + unsigned int partition_count = pi.partition_count; + ei.ep.partition_count = partition_count; + promise(partition_count > 0); + + unsigned int texel_count = blk.texel_count; + promise(texel_count > 0); + + float error_weight; + const float* data_vr = nullptr; + + assert(component < BLOCK_MAX_COMPONENTS); + switch (component) + { + case 0: + error_weight = blk.channel_weight.lane<0>(); + data_vr = blk.data_r; + break; + case 1: + error_weight = blk.channel_weight.lane<1>(); + data_vr = blk.data_g; + break; + case 2: + error_weight = blk.channel_weight.lane<2>(); + data_vr = blk.data_b; + break; + default: + assert(component == 3); + error_weight = blk.channel_weight.lane<3>(); + data_vr = blk.data_a; + break; + } + + vmask4 sep_mask = vint4::lane_id() == vint4(component); + bool is_constant_wes { true }; + float partition0_len_sq { 0.0f }; + + for (unsigned int i = 0; i < partition_count; i++) + { + float lowvalue { 1e10f }; + float highvalue { -1e10f }; + + unsigned int partition_texel_count = pi.partition_texel_count[i]; + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + float value = data_vr[tix]; + lowvalue = astc::min(value, lowvalue); + highvalue = astc::max(value, highvalue); + } + + if (highvalue <= lowvalue) + { + lowvalue = 0.0f; + highvalue = 1e-7f; + } + + float length = highvalue - lowvalue; + float length_squared = length * length; + float scale = 1.0f / length; + + if (i == 0) + { + partition0_len_sq = length_squared; + } + else + { + is_constant_wes = is_constant_wes && length_squared == partition0_len_sq; + } + + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + float value = (data_vr[tix] - lowvalue) * scale; + value = astc::clamp1f(value); + + ei.weights[tix] = value; + ei.weight_error_scale[tix] = length_squared * error_weight; + assert(!astc::isnan(ei.weight_error_scale[tix])); + } + + ei.ep.endpt0[i] = select(blk.data_min, vfloat4(lowvalue), sep_mask); + ei.ep.endpt1[i] = select(blk.data_max, vfloat4(highvalue), sep_mask); + } + + // Zero initialize any SIMD over-fetch + unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count); + for (unsigned int i = texel_count; i < texel_count_simd; i++) + { + ei.weights[i] = 0.0f; + ei.weight_error_scale[i] = 0.0f; + } + + ei.is_constant_weight_error_scale = is_constant_wes; +} + +/** + * @brief Compute the ideal endpoints and weights for 2 color components. + * + * @param blk The image block color data to compress. + * @param pi The partition info for the current trial. + * @param[out] ei The computed ideal endpoints and weights. + * @param component1 The first color component to compute. + * @param component2 The second color component to compute. + */ +static void compute_ideal_colors_and_weights_2_comp( + const image_block& blk, + const partition_info& pi, + endpoints_and_weights& ei, + int component1, + int component2 +) { + unsigned int partition_count = pi.partition_count; + ei.ep.partition_count = partition_count; + promise(partition_count > 0); + + unsigned int texel_count = blk.texel_count; + promise(texel_count > 0); + + partition_metrics pms[BLOCK_MAX_PARTITIONS]; + + float error_weight; + const float* data_vr = nullptr; + const float* data_vg = nullptr; + + if (component1 == 0 && component2 == 1) + { + error_weight = hadd_s(blk.channel_weight.swz<0, 1>()) / 2.0f; + + data_vr = blk.data_r; + data_vg = blk.data_g; + } + else if (component1 == 0 && component2 == 2) + { + error_weight = hadd_s(blk.channel_weight.swz<0, 2>()) / 2.0f; + + data_vr = blk.data_r; + data_vg = blk.data_b; + } + else // (component1 == 1 && component2 == 2) + { + assert(component1 == 1 && component2 == 2); + + error_weight = hadd_s(blk.channel_weight.swz<1, 2>()) / 2.0f; + + data_vr = blk.data_g; + data_vg = blk.data_b; + } + + compute_avgs_and_dirs_2_comp(pi, blk, component1, component2, pms); + + bool is_constant_wes { true }; + float partition0_len_sq { 0.0f }; + + vmask4 comp1_mask = vint4::lane_id() == vint4(component1); + vmask4 comp2_mask = vint4::lane_id() == vint4(component2); + + for (unsigned int i = 0; i < partition_count; i++) + { + vfloat4 dir = pms[i].dir; + if (hadd_s(dir) < 0.0f) + { + dir = vfloat4::zero() - dir; + } + + line2 line { pms[i].avg, normalize_safe(dir, unit2()) }; + float lowparam { 1e10f }; + float highparam { -1e10f }; + + unsigned int partition_texel_count = pi.partition_texel_count[i]; + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + vfloat4 point = vfloat2(data_vr[tix], data_vg[tix]); + float param = dot_s(point - line.a, line.b); + ei.weights[tix] = param; + + lowparam = astc::min(param, lowparam); + highparam = astc::max(param, highparam); + } + + // It is possible for a uniform-color partition to produce length=0; + // this causes NaN issues so set to small value to avoid this problem + if (highparam <= lowparam) + { + lowparam = 0.0f; + highparam = 1e-7f; + } + + float length = highparam - lowparam; + float length_squared = length * length; + float scale = 1.0f / length; + + if (i == 0) + { + partition0_len_sq = length_squared; + } + else + { + is_constant_wes = is_constant_wes && length_squared == partition0_len_sq; + } + + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + float idx = (ei.weights[tix] - lowparam) * scale; + idx = astc::clamp1f(idx); + + ei.weights[tix] = idx; + ei.weight_error_scale[tix] = length_squared * error_weight; + assert(!astc::isnan(ei.weight_error_scale[tix])); + } + + vfloat4 lowvalue = line.a + line.b * lowparam; + vfloat4 highvalue = line.a + line.b * highparam; + + vfloat4 ep0 = select(blk.data_min, vfloat4(lowvalue.lane<0>()), comp1_mask); + vfloat4 ep1 = select(blk.data_max, vfloat4(highvalue.lane<0>()), comp1_mask); + + ei.ep.endpt0[i] = select(ep0, vfloat4(lowvalue.lane<1>()), comp2_mask); + ei.ep.endpt1[i] = select(ep1, vfloat4(highvalue.lane<1>()), comp2_mask); + } + + // Zero initialize any SIMD over-fetch + unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count); + for (unsigned int i = texel_count; i < texel_count_simd; i++) + { + ei.weights[i] = 0.0f; + ei.weight_error_scale[i] = 0.0f; + } + + ei.is_constant_weight_error_scale = is_constant_wes; +} + +/** + * @brief Compute the ideal endpoints and weights for 3 color components. + * + * @param blk The image block color data to compress. + * @param pi The partition info for the current trial. + * @param[out] ei The computed ideal endpoints and weights. + * @param omitted_component The color component excluded from the calculation. + */ +static void compute_ideal_colors_and_weights_3_comp( + const image_block& blk, + const partition_info& pi, + endpoints_and_weights& ei, + unsigned int omitted_component +) { + unsigned int partition_count = pi.partition_count; + ei.ep.partition_count = partition_count; + promise(partition_count > 0); + + unsigned int texel_count = blk.texel_count; + promise(texel_count > 0); + + partition_metrics pms[BLOCK_MAX_PARTITIONS]; + + float error_weight; + const float* data_vr = nullptr; + const float* data_vg = nullptr; + const float* data_vb = nullptr; + if (omitted_component == 0) + { + error_weight = hadd_s(blk.channel_weight.swz<0, 1, 2>()); + data_vr = blk.data_g; + data_vg = blk.data_b; + data_vb = blk.data_a; + } + else if (omitted_component == 1) + { + error_weight = hadd_s(blk.channel_weight.swz<0, 2, 3>()); + data_vr = blk.data_r; + data_vg = blk.data_b; + data_vb = blk.data_a; + } + else if (omitted_component == 2) + { + error_weight = hadd_s(blk.channel_weight.swz<0, 1, 3>()); + data_vr = blk.data_r; + data_vg = blk.data_g; + data_vb = blk.data_a; + } + else + { + assert(omitted_component == 3); + + error_weight = hadd_s(blk.channel_weight.swz<0, 1, 2>()); + data_vr = blk.data_r; + data_vg = blk.data_g; + data_vb = blk.data_b; + } + + error_weight = error_weight * (1.0f / 3.0f); + + if (omitted_component == 3) + { + compute_avgs_and_dirs_3_comp_rgb(pi, blk, pms); + } + else + { + compute_avgs_and_dirs_3_comp(pi, blk, omitted_component, pms); + } + + bool is_constant_wes { true }; + float partition0_len_sq { 0.0f }; + + for (unsigned int i = 0; i < partition_count; i++) + { + vfloat4 dir = pms[i].dir; + if (hadd_rgb_s(dir) < 0.0f) + { + dir = vfloat4::zero() - dir; + } + + line3 line { pms[i].avg, normalize_safe(dir, unit3()) }; + float lowparam { 1e10f }; + float highparam { -1e10f }; + + unsigned int partition_texel_count = pi.partition_texel_count[i]; + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + vfloat4 point = vfloat3(data_vr[tix], data_vg[tix], data_vb[tix]); + float param = dot3_s(point - line.a, line.b); + ei.weights[tix] = param; + + lowparam = astc::min(param, lowparam); + highparam = astc::max(param, highparam); + } + + // It is possible for a uniform-color partition to produce length=0; + // this causes NaN issues so set to small value to avoid this problem + if (highparam <= lowparam) + { + lowparam = 0.0f; + highparam = 1e-7f; + } + + float length = highparam - lowparam; + float length_squared = length * length; + float scale = 1.0f / length; + + if (i == 0) + { + partition0_len_sq = length_squared; + } + else + { + is_constant_wes = is_constant_wes && length_squared == partition0_len_sq; + } + + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + float idx = (ei.weights[tix] - lowparam) * scale; + idx = astc::clamp1f(idx); + + ei.weights[tix] = idx; + ei.weight_error_scale[tix] = length_squared * error_weight; + assert(!astc::isnan(ei.weight_error_scale[tix])); + } + + vfloat4 ep0 = line.a + line.b * lowparam; + vfloat4 ep1 = line.a + line.b * highparam; + + vfloat4 bmin = blk.data_min; + vfloat4 bmax = blk.data_max; + + assert(omitted_component < BLOCK_MAX_COMPONENTS); + switch (omitted_component) + { + case 0: + ei.ep.endpt0[i] = vfloat4(bmin.lane<0>(), ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>()); + ei.ep.endpt1[i] = vfloat4(bmax.lane<0>(), ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>()); + break; + case 1: + ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), bmin.lane<1>(), ep0.lane<1>(), ep0.lane<2>()); + ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), bmax.lane<1>(), ep1.lane<1>(), ep1.lane<2>()); + break; + case 2: + ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), bmin.lane<2>(), ep0.lane<2>()); + ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), bmax.lane<2>(), ep1.lane<2>()); + break; + default: + ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), bmin.lane<3>()); + ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>(), bmax.lane<3>()); + break; + } + } + + // Zero initialize any SIMD over-fetch + unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count); + for (unsigned int i = texel_count; i < texel_count_simd; i++) + { + ei.weights[i] = 0.0f; + ei.weight_error_scale[i] = 0.0f; + } + + ei.is_constant_weight_error_scale = is_constant_wes; +} + +/** + * @brief Compute the ideal endpoints and weights for 4 color components. + * + * @param blk The image block color data to compress. + * @param pi The partition info for the current trial. + * @param[out] ei The computed ideal endpoints and weights. + */ +static void compute_ideal_colors_and_weights_4_comp( + const image_block& blk, + const partition_info& pi, + endpoints_and_weights& ei +) { + const float error_weight = hadd_s(blk.channel_weight) / 4.0f; + + unsigned int partition_count = pi.partition_count; + + unsigned int texel_count = blk.texel_count; + promise(texel_count > 0); + promise(partition_count > 0); + + partition_metrics pms[BLOCK_MAX_PARTITIONS]; + + compute_avgs_and_dirs_4_comp(pi, blk, pms); + + bool is_constant_wes { true }; + float partition0_len_sq { 0.0f }; + + for (unsigned int i = 0; i < partition_count; i++) + { + vfloat4 dir = pms[i].dir; + if (hadd_rgb_s(dir) < 0.0f) + { + dir = vfloat4::zero() - dir; + } + + line4 line { pms[i].avg, normalize_safe(dir, unit4()) }; + float lowparam { 1e10f }; + float highparam { -1e10f }; + + unsigned int partition_texel_count = pi.partition_texel_count[i]; + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + vfloat4 point = blk.texel(tix); + float param = dot_s(point - line.a, line.b); + ei.weights[tix] = param; + + lowparam = astc::min(param, lowparam); + highparam = astc::max(param, highparam); + } + + // It is possible for a uniform-color partition to produce length=0; + // this causes NaN issues so set to small value to avoid this problem + if (highparam <= lowparam) + { + lowparam = 0.0f; + highparam = 1e-7f; + } + + float length = highparam - lowparam; + float length_squared = length * length; + float scale = 1.0f / length; + + if (i == 0) + { + partition0_len_sq = length_squared; + } + else + { + is_constant_wes = is_constant_wes && length_squared == partition0_len_sq; + } + + ei.ep.endpt0[i] = line.a + line.b * lowparam; + ei.ep.endpt1[i] = line.a + line.b * highparam; + + for (unsigned int j = 0; j < partition_texel_count; j++) + { + unsigned int tix = pi.texels_of_partition[i][j]; + float idx = (ei.weights[tix] - lowparam) * scale; + idx = astc::clamp1f(idx); + + ei.weights[tix] = idx; + ei.weight_error_scale[tix] = length_squared * error_weight; + assert(!astc::isnan(ei.weight_error_scale[tix])); + } + } + + // Zero initialize any SIMD over-fetch + unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count); + for (unsigned int i = texel_count; i < texel_count_simd; i++) + { + ei.weights[i] = 0.0f; + ei.weight_error_scale[i] = 0.0f; + } + + ei.is_constant_weight_error_scale = is_constant_wes; +} + +/* See header for documentation. */ +void compute_ideal_colors_and_weights_1plane( + const image_block& blk, + const partition_info& pi, + endpoints_and_weights& ei +) { + bool uses_alpha = !blk.is_constant_channel(3); + + if (uses_alpha) + { + compute_ideal_colors_and_weights_4_comp(blk, pi, ei); + } + else + { + compute_ideal_colors_and_weights_3_comp(blk, pi, ei, 3); + } +} + +/* See header for documentation. */ +void compute_ideal_colors_and_weights_2planes( + const block_size_descriptor& bsd, + const image_block& blk, + unsigned int plane2_component, + endpoints_and_weights& ei1, + endpoints_and_weights& ei2 +) { + const auto& pi = bsd.get_partition_info(1, 0); + bool uses_alpha = !blk.is_constant_channel(3); + + assert(plane2_component < BLOCK_MAX_COMPONENTS); + switch (plane2_component) + { + case 0: // Separate weights for red + if (uses_alpha) + { + compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 0); + } + else + { + compute_ideal_colors_and_weights_2_comp(blk, pi, ei1, 1, 2); + } + compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 0); + break; + + case 1: // Separate weights for green + if (uses_alpha) + { + compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 1); + } + else + { + compute_ideal_colors_and_weights_2_comp(blk, pi, ei1, 0, 2); + } + compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 1); + break; + + case 2: // Separate weights for blue + if (uses_alpha) + { + compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 2); + } + else + { + compute_ideal_colors_and_weights_2_comp(blk, pi, ei1, 0, 1); + } + compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 2); + break; + + default: // Separate weights for alpha + assert(uses_alpha); + compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 3); + compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 3); + break; + } +} + +/* See header for documentation. */ +float compute_error_of_weight_set_1plane( + const endpoints_and_weights& eai, + const decimation_info& di, + const float* dec_weight_quant_uvalue +) { + vfloatacc error_summav = vfloatacc::zero(); + unsigned int texel_count = di.texel_count; + promise(texel_count > 0); + + // Process SIMD-width chunks, safe to over-fetch - the extra space is zero initialized + if (di.max_texel_weight_count > 2) + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Compute the bilinear interpolation of the decimated weight grid + vfloat current_values = bilinear_infill_vla(di, dec_weight_quant_uvalue, i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values = loada(eai.weights + i); + vfloat diff = current_values - actual_values; + vfloat significance = loada(eai.weight_error_scale + i); + vfloat error = diff * diff * significance; + + haccumulate(error_summav, error); + } + } + else if (di.max_texel_weight_count > 1) + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Compute the bilinear interpolation of the decimated weight grid + vfloat current_values = bilinear_infill_vla_2(di, dec_weight_quant_uvalue, i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values = loada(eai.weights + i); + vfloat diff = current_values - actual_values; + vfloat significance = loada(eai.weight_error_scale + i); + vfloat error = diff * diff * significance; + + haccumulate(error_summav, error); + } + } + else + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Load the weight set directly, without interpolation + vfloat current_values = loada(dec_weight_quant_uvalue + i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values = loada(eai.weights + i); + vfloat diff = current_values - actual_values; + vfloat significance = loada(eai.weight_error_scale + i); + vfloat error = diff * diff * significance; + + haccumulate(error_summav, error); + } + } + + // Resolve the final scalar accumulator sum + return hadd_s(error_summav); +} + +/* See header for documentation. */ +float compute_error_of_weight_set_2planes( + const endpoints_and_weights& eai1, + const endpoints_and_weights& eai2, + const decimation_info& di, + const float* dec_weight_quant_uvalue_plane1, + const float* dec_weight_quant_uvalue_plane2 +) { + vfloatacc error_summav = vfloatacc::zero(); + unsigned int texel_count = di.texel_count; + promise(texel_count > 0); + + // Process SIMD-width chunks, safe to over-fetch - the extra space is zero initialized + if (di.max_texel_weight_count > 2) + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Plane 1 + // Compute the bilinear interpolation of the decimated weight grid + vfloat current_values1 = bilinear_infill_vla(di, dec_weight_quant_uvalue_plane1, i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values1 = loada(eai1.weights + i); + vfloat diff = current_values1 - actual_values1; + vfloat error1 = diff * diff * loada(eai1.weight_error_scale + i); + + // Plane 2 + // Compute the bilinear interpolation of the decimated weight grid + vfloat current_values2 = bilinear_infill_vla(di, dec_weight_quant_uvalue_plane2, i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values2 = loada(eai2.weights + i); + diff = current_values2 - actual_values2; + vfloat error2 = diff * diff * loada(eai2.weight_error_scale + i); + + haccumulate(error_summav, error1 + error2); + } + } + else if (di.max_texel_weight_count > 1) + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Plane 1 + // Compute the bilinear interpolation of the decimated weight grid + vfloat current_values1 = bilinear_infill_vla_2(di, dec_weight_quant_uvalue_plane1, i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values1 = loada(eai1.weights + i); + vfloat diff = current_values1 - actual_values1; + vfloat error1 = diff * diff * loada(eai1.weight_error_scale + i); + + // Plane 2 + // Compute the bilinear interpolation of the decimated weight grid + vfloat current_values2 = bilinear_infill_vla_2(di, dec_weight_quant_uvalue_plane2, i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values2 = loada(eai2.weights + i); + diff = current_values2 - actual_values2; + vfloat error2 = diff * diff * loada(eai2.weight_error_scale + i); + + haccumulate(error_summav, error1 + error2); + } + } + else + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + // Plane 1 + // Load the weight set directly, without interpolation + vfloat current_values1 = loada(dec_weight_quant_uvalue_plane1 + i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values1 = loada(eai1.weights + i); + vfloat diff = current_values1 - actual_values1; + vfloat error1 = diff * diff * loada(eai1.weight_error_scale + i); + + // Plane 2 + // Load the weight set directly, without interpolation + vfloat current_values2 = loada(dec_weight_quant_uvalue_plane2 + i); + + // Compute the error between the computed value and the ideal weight + vfloat actual_values2 = loada(eai2.weights + i); + diff = current_values2 - actual_values2; + vfloat error2 = diff * diff * loada(eai2.weight_error_scale + i); + + haccumulate(error_summav, error1 + error2); + } + } + + // Resolve the final scalar accumulator sum + return hadd_s(error_summav); +} + +/* See header for documentation. */ +void compute_ideal_weights_for_decimation( + const endpoints_and_weights& ei, + const decimation_info& di, + float* dec_weight_ideal_value +) { + unsigned int texel_count = di.texel_count; + unsigned int weight_count = di.weight_count; + bool is_direct = texel_count == weight_count; + promise(texel_count > 0); + promise(weight_count > 0); + + // Ensure that the end of the output arrays that are used for SIMD paths later are filled so we + // can safely run SIMD elsewhere without a loop tail. Note that this is always safe as weight + // arrays always contain space for 64 elements + unsigned int prev_weight_count_simd = round_down_to_simd_multiple_vla(weight_count - 1); + storea(vfloat::zero(), dec_weight_ideal_value + prev_weight_count_simd); + + // If we have a 1:1 mapping just shortcut the computation. Transfer enough to also copy the + // zero-initialized SIMD over-fetch region + if (is_direct) + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight(ei.weights + i); + storea(weight, dec_weight_ideal_value + i); + } + + return; + } + + // Otherwise compute an estimate and perform single refinement iteration + alignas(ASTCENC_VECALIGN) float infilled_weights[BLOCK_MAX_TEXELS]; + + // Compute an initial average for each decimated weight + bool constant_wes = ei.is_constant_weight_error_scale; + vfloat weight_error_scale(ei.weight_error_scale[0]); + + // This overshoots - this is OK as we initialize the array tails in the + // decimation table structures to safe values ... + for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + // Start with a small value to avoid div-by-zero later + vfloat weight_weight(1e-10f); + vfloat initial_weight = vfloat::zero(); + + // Accumulate error weighting of all the texels using this weight + vint weight_texel_count(di.weight_texel_count + i); + unsigned int max_texel_count = hmax(weight_texel_count).lane<0>(); + promise(max_texel_count > 0); + + for (unsigned int j = 0; j < max_texel_count; j++) + { + vint texel(di.weight_texels_tr[j] + i); + vfloat weight = loada(di.weights_texel_contribs_tr[j] + i); + + if (!constant_wes) + { + weight_error_scale = gatherf(ei.weight_error_scale, texel); + } + + vfloat contrib_weight = weight * weight_error_scale; + + weight_weight += contrib_weight; + initial_weight += gatherf(ei.weights, texel) * contrib_weight; + } + + storea(initial_weight / weight_weight, dec_weight_ideal_value + i); + } + + // Populate the interpolated weight grid based on the initial average + // Process SIMD-width texel coordinates at at time while we can. Safe to + // over-process full SIMD vectors - the tail is zeroed. + if (di.max_texel_weight_count <= 2) + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight = bilinear_infill_vla_2(di, dec_weight_ideal_value, i); + storea(weight, infilled_weights + i); + } + } + else + { + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight = bilinear_infill_vla(di, dec_weight_ideal_value, i); + storea(weight, infilled_weights + i); + } + } + + // Perform a single iteration of refinement + // Empirically determined step size; larger values don't help but smaller drops image quality + constexpr float stepsize = 0.25f; + constexpr float chd_scale = -WEIGHTS_TEXEL_SUM; + + for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight_val = loada(dec_weight_ideal_value + i); + + // Accumulate error weighting of all the texels using this weight + // Start with a small value to avoid div-by-zero later + vfloat error_change0(1e-10f); + vfloat error_change1(0.0f); + + // Accumulate error weighting of all the texels using this weight + vint weight_texel_count(di.weight_texel_count + i); + unsigned int max_texel_count = hmax(weight_texel_count).lane<0>(); + promise(max_texel_count > 0); + + for (unsigned int j = 0; j < max_texel_count; j++) + { + vint texel(di.weight_texels_tr[j] + i); + vfloat contrib_weight = loada(di.weights_texel_contribs_tr[j] + i); + + if (!constant_wes) + { + weight_error_scale = gatherf(ei.weight_error_scale, texel); + } + + vfloat scale = weight_error_scale * contrib_weight; + vfloat old_weight = gatherf(infilled_weights, texel); + vfloat ideal_weight = gatherf(ei.weights, texel); + + error_change0 += contrib_weight * scale; + error_change1 += (old_weight - ideal_weight) * scale; + } + + vfloat step = (error_change1 * chd_scale) / error_change0; + step = clamp(-stepsize, stepsize, step); + + // Update the weight; note this can store negative values + storea(weight_val + step, dec_weight_ideal_value + i); + } +} + +/* See header for documentation. */ +void compute_quantized_weights_for_decimation( + const decimation_info& di, + float low_bound, + float high_bound, + const float* dec_weight_ideal_value, + float* weight_set_out, + uint8_t* quantized_weight_set, + quant_method quant_level +) { + int weight_count = di.weight_count; + promise(weight_count > 0); + const quant_and_transfer_table& qat = quant_and_xfer_tables[quant_level]; + + // The available quant levels, stored with a minus 1 bias + static const float quant_levels_m1[12] { + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 9.0f, 11.0f, 15.0f, 19.0f, 23.0f, 31.0f + }; + + vint steps_m1(get_quant_level(quant_level) - 1); + float quant_level_m1 = quant_levels_m1[quant_level]; + + // Quantize the weight set using both the specified low/high bounds and standard 0..1 bounds + + // TODO: Oddity to investigate; triggered by test in issue #265. + if (high_bound <= low_bound) + { + low_bound = 0.0f; + high_bound = 1.0f; + } + + float rscale = high_bound - low_bound; + float scale = 1.0f / rscale; + + float scaled_low_bound = low_bound * scale; + rscale *= 1.0f / 64.0f; + + vfloat scalev(scale); + vfloat scaled_low_boundv(scaled_low_bound); + vfloat quant_level_m1v(quant_level_m1); + vfloat rscalev(rscale); + vfloat low_boundv(low_bound); + + // This runs to the rounded-up SIMD size, which is safe as the loop tail is filled with known + // safe data in compute_ideal_weights_for_decimation and arrays are always 64 elements + if (get_quant_level(quant_level) <= 16) + { + vint4 tab0(reinterpret_cast<const int*>(qat.quant_to_unquant)); + vint tab0p; + vtable_prepare(tab0, tab0p); + + for (int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat ix = loada(dec_weight_ideal_value + i) * scalev - scaled_low_boundv; + ix = clampzo(ix); + + // Look up the two closest indexes and return the one that was closest + vfloat ix1 = ix * quant_level_m1v; + + vint weightl = float_to_int(ix1); + vint weighth = min(weightl + vint(1), steps_m1); + + vint ixli = vtable_8bt_32bi(tab0p, weightl); + vint ixhi = vtable_8bt_32bi(tab0p, weighth); + + vfloat ixl = int_to_float(ixli); + vfloat ixh = int_to_float(ixhi); + + vmask mask = (ixl + ixh) < (vfloat(128.0f) * ix); + vint weight = select(ixli, ixhi, mask); + ixl = select(ixl, ixh, mask); + + // Invert the weight-scaling that was done initially + storea(ixl * rscalev + low_boundv, weight_set_out + i); + vint scn = pack_low_bytes(weight); + store_nbytes(scn, quantized_weight_set + i); + } + } + else + { + vint4 tab0(reinterpret_cast<const int*>(qat.quant_to_unquant)); + vint4 tab1(reinterpret_cast<const int*>(qat.quant_to_unquant + 16)); + vint tab0p, tab1p; + vtable_prepare(tab0, tab1, tab0p, tab1p); + + for (int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat ix = loada(dec_weight_ideal_value + i) * scalev - scaled_low_boundv; + ix = clampzo(ix); + + // Look up the two closest indexes and return the one that was closest + vfloat ix1 = ix * quant_level_m1v; + + vint weightl = float_to_int(ix1); + vint weighth = min(weightl + vint(1), steps_m1); + + vint ixli = vtable_8bt_32bi(tab0p, tab1p, weightl); + vint ixhi = vtable_8bt_32bi(tab0p, tab1p, weighth); + + vfloat ixl = int_to_float(ixli); + vfloat ixh = int_to_float(ixhi); + + vmask mask = (ixl + ixh) < (vfloat(128.0f) * ix); + vint weight = select(ixli, ixhi, mask); + ixl = select(ixl, ixh, mask); + + // Invert the weight-scaling that was done initially + storea(ixl * rscalev + low_boundv, weight_set_out + i); + vint scn = pack_low_bytes(weight); + store_nbytes(scn, quantized_weight_set + i); + } + } +} + +/** + * @brief Compute the RGB + offset for a HDR endpoint mode #7. + * + * Since the matrix needed has a regular structure we can simplify the inverse calculation. This + * gives us ~24 multiplications vs. 96 for a generic inverse. + * + * mat[0] = vfloat4(rgba_ws.x, 0.0f, 0.0f, wght_ws.x); + * mat[1] = vfloat4( 0.0f, rgba_ws.y, 0.0f, wght_ws.y); + * mat[2] = vfloat4( 0.0f, 0.0f, rgba_ws.z, wght_ws.z); + * mat[3] = vfloat4(wght_ws.x, wght_ws.y, wght_ws.z, psum); + * mat = invert(mat); + * + * @param rgba_weight_sum Sum of partition component error weights. + * @param weight_weight_sum Sum of partition component error weights * texel weight. + * @param rgbq_sum Sum of partition component error weights * texel weight * color data. + * @param psum Sum of RGB color weights * texel weight^2. + */ +static inline vfloat4 compute_rgbo_vector( + vfloat4 rgba_weight_sum, + vfloat4 weight_weight_sum, + vfloat4 rgbq_sum, + float psum +) { + float X = rgba_weight_sum.lane<0>(); + float Y = rgba_weight_sum.lane<1>(); + float Z = rgba_weight_sum.lane<2>(); + float P = weight_weight_sum.lane<0>(); + float Q = weight_weight_sum.lane<1>(); + float R = weight_weight_sum.lane<2>(); + float S = psum; + + float PP = P * P; + float QQ = Q * Q; + float RR = R * R; + + float SZmRR = S * Z - RR; + float DT = SZmRR * Y - Z * QQ; + float YP = Y * P; + float QX = Q * X; + float YX = Y * X; + float mZYP = -Z * YP; + float mZQX = -Z * QX; + float mRYX = -R * YX; + float ZQP = Z * Q * P; + float RYP = R * YP; + float RQX = R * QX; + + // Compute the reciprocal of matrix determinant + float rdet = 1.0f / (DT * X + mZYP * P); + + // Actually compute the adjugate, and then apply 1/det separately + vfloat4 mat0(DT, ZQP, RYP, mZYP); + vfloat4 mat1(ZQP, SZmRR * X - Z * PP, RQX, mZQX); + vfloat4 mat2(RYP, RQX, (S * Y - QQ) * X - Y * PP, mRYX); + vfloat4 mat3(mZYP, mZQX, mRYX, Z * YX); + vfloat4 vect = rgbq_sum * rdet; + + return vfloat4(dot_s(mat0, vect), + dot_s(mat1, vect), + dot_s(mat2, vect), + dot_s(mat3, vect)); +} + +/* See header for documentation. */ +void recompute_ideal_colors_1plane( + const image_block& blk, + const partition_info& pi, + const decimation_info& di, + const uint8_t* dec_weights_uquant, + endpoints& ep, + vfloat4 rgbs_vectors[BLOCK_MAX_PARTITIONS], + vfloat4 rgbo_vectors[BLOCK_MAX_PARTITIONS] +) { + unsigned int weight_count = di.weight_count; + unsigned int total_texel_count = blk.texel_count; + unsigned int partition_count = pi.partition_count; + + promise(weight_count > 0); + promise(total_texel_count > 0); + promise(partition_count > 0); + + alignas(ASTCENC_VECALIGN) float dec_weight[BLOCK_MAX_WEIGHTS]; + for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + vint unquant_value(dec_weights_uquant + i); + vfloat unquant_valuef = int_to_float(unquant_value) * vfloat(1.0f / 64.0f); + storea(unquant_valuef, dec_weight + i); + } + + alignas(ASTCENC_VECALIGN) float undec_weight[BLOCK_MAX_TEXELS]; + float* undec_weight_ref; + if (di.max_texel_weight_count == 1) + { + undec_weight_ref = dec_weight; + } + else if (di.max_texel_weight_count <= 2) + { + for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight = bilinear_infill_vla_2(di, dec_weight, i); + storea(weight, undec_weight + i); + } + + undec_weight_ref = undec_weight; + } + else + { + for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight = bilinear_infill_vla(di, dec_weight, i); + storea(weight, undec_weight + i); + } + + undec_weight_ref = undec_weight; + } + + vfloat4 rgba_sum(blk.data_mean * static_cast<float>(blk.texel_count)); + + for (unsigned int i = 0; i < partition_count; i++) + { + unsigned int texel_count = pi.partition_texel_count[i]; + const uint8_t *texel_indexes = pi.texels_of_partition[i]; + + // Only compute a partition mean if more than one partition + if (partition_count > 1) + { + rgba_sum = vfloat4::zero(); + promise(texel_count > 0); + for (unsigned int j = 0; j < texel_count; j++) + { + unsigned int tix = texel_indexes[j]; + rgba_sum += blk.texel(tix); + } + } + + rgba_sum = rgba_sum * blk.channel_weight; + vfloat4 rgba_weight_sum = max(blk.channel_weight * static_cast<float>(texel_count), 1e-17f); + vfloat4 scale_dir = normalize((rgba_sum / rgba_weight_sum).swz<0, 1, 2>()); + + float scale_max = 0.0f; + float scale_min = 1e10f; + + float wmin1 = 1.0f; + float wmax1 = 0.0f; + + float left_sum_s = 0.0f; + float middle_sum_s = 0.0f; + float right_sum_s = 0.0f; + + vfloat4 color_vec_x = vfloat4::zero(); + vfloat4 color_vec_y = vfloat4::zero(); + + vfloat4 scale_vec = vfloat4::zero(); + + float weight_weight_sum_s = 1e-17f; + + vfloat4 color_weight = blk.channel_weight; + float ls_weight = hadd_rgb_s(color_weight); + + for (unsigned int j = 0; j < texel_count; j++) + { + unsigned int tix = texel_indexes[j]; + vfloat4 rgba = blk.texel(tix); + + float idx0 = undec_weight_ref[tix]; + + float om_idx0 = 1.0f - idx0; + wmin1 = astc::min(idx0, wmin1); + wmax1 = astc::max(idx0, wmax1); + + float scale = dot3_s(scale_dir, rgba); + scale_min = astc::min(scale, scale_min); + scale_max = astc::max(scale, scale_max); + + left_sum_s += om_idx0 * om_idx0; + middle_sum_s += om_idx0 * idx0; + right_sum_s += idx0 * idx0; + weight_weight_sum_s += idx0; + + vfloat4 color_idx(idx0); + vfloat4 cwprod = rgba; + vfloat4 cwiprod = cwprod * color_idx; + + color_vec_y += cwiprod; + color_vec_x += cwprod - cwiprod; + + scale_vec += vfloat2(om_idx0, idx0) * (scale * ls_weight); + } + + vfloat4 left_sum = vfloat4(left_sum_s) * color_weight; + vfloat4 middle_sum = vfloat4(middle_sum_s) * color_weight; + vfloat4 right_sum = vfloat4(right_sum_s) * color_weight; + vfloat4 lmrs_sum = vfloat3(left_sum_s, middle_sum_s, right_sum_s) * ls_weight; + + color_vec_x = color_vec_x * color_weight; + color_vec_y = color_vec_y * color_weight; + + // Initialize the luminance and scale vectors with a reasonable default + float scalediv = scale_min / astc::max(scale_max, 1e-10f); + scalediv = astc::clamp1f(scalediv); + + vfloat4 sds = scale_dir * scale_max; + + rgbs_vectors[i] = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), scalediv); + + if (wmin1 >= wmax1 * 0.999f) + { + // If all weights in the partition were equal, then just take average of all colors in + // the partition and use that as both endpoint colors + vfloat4 avg = (color_vec_x + color_vec_y) / rgba_weight_sum; + + vmask4 notnan_mask = avg == avg; + ep.endpt0[i] = select(ep.endpt0[i], avg, notnan_mask); + ep.endpt1[i] = select(ep.endpt1[i], avg, notnan_mask); + + rgbs_vectors[i] = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), 1.0f); + } + else + { + // Otherwise, complete the analytic calculation of ideal-endpoint-values for the given + // set of texel weights and pixel colors + vfloat4 color_det1 = (left_sum * right_sum) - (middle_sum * middle_sum); + vfloat4 color_rdet1 = 1.0f / color_det1; + + float ls_det1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<2>()) - (lmrs_sum.lane<1>() * lmrs_sum.lane<1>()); + float ls_rdet1 = 1.0f / ls_det1; + + vfloat4 color_mss1 = (left_sum * left_sum) + + (2.0f * middle_sum * middle_sum) + + (right_sum * right_sum); + + float ls_mss1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<0>()) + + (2.0f * lmrs_sum.lane<1>() * lmrs_sum.lane<1>()) + + (lmrs_sum.lane<2>() * lmrs_sum.lane<2>()); + + vfloat4 ep0 = (right_sum * color_vec_x - middle_sum * color_vec_y) * color_rdet1; + vfloat4 ep1 = (left_sum * color_vec_y - middle_sum * color_vec_x) * color_rdet1; + + vmask4 det_mask = abs(color_det1) > (color_mss1 * 1e-4f); + vmask4 notnan_mask = (ep0 == ep0) & (ep1 == ep1); + vmask4 full_mask = det_mask & notnan_mask; + + ep.endpt0[i] = select(ep.endpt0[i], ep0, full_mask); + ep.endpt1[i] = select(ep.endpt1[i], ep1, full_mask); + + float scale_ep0 = (lmrs_sum.lane<2>() * scale_vec.lane<0>() - lmrs_sum.lane<1>() * scale_vec.lane<1>()) * ls_rdet1; + float scale_ep1 = (lmrs_sum.lane<0>() * scale_vec.lane<1>() - lmrs_sum.lane<1>() * scale_vec.lane<0>()) * ls_rdet1; + + if (fabsf(ls_det1) > (ls_mss1 * 1e-4f) && scale_ep0 == scale_ep0 && scale_ep1 == scale_ep1 && scale_ep0 < scale_ep1) + { + float scalediv2 = scale_ep0 / scale_ep1; + vfloat4 sdsm = scale_dir * scale_ep1; + rgbs_vectors[i] = vfloat4(sdsm.lane<0>(), sdsm.lane<1>(), sdsm.lane<2>(), scalediv2); + } + } + + // Calculations specific to mode #7, the HDR RGB-scale mode - skip if known LDR + if (blk.rgb_lns[0] || blk.alpha_lns[0]) + { + vfloat4 weight_weight_sum = vfloat4(weight_weight_sum_s) * color_weight; + float psum = right_sum_s * hadd_rgb_s(color_weight); + + vfloat4 rgbq_sum = color_vec_x + color_vec_y; + rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y)); + + vfloat4 rgbovec = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum); + rgbo_vectors[i] = rgbovec; + + // We can get a failure due to the use of a singular (non-invertible) matrix + // If it failed, compute rgbo_vectors[] with a different method ... + if (astc::isnan(dot_s(rgbovec, rgbovec))) + { + vfloat4 v0 = ep.endpt0[i]; + vfloat4 v1 = ep.endpt1[i]; + + float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f); + avgdif = astc::max(avgdif, 0.0f); + + vfloat4 avg = (v0 + v1) * 0.5f; + vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f; + rgbo_vectors[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif); + } + } + } +} + +/* See header for documentation. */ +void recompute_ideal_colors_2planes( + const image_block& blk, + const block_size_descriptor& bsd, + const decimation_info& di, + const uint8_t* dec_weights_uquant_plane1, + const uint8_t* dec_weights_uquant_plane2, + endpoints& ep, + vfloat4& rgbs_vector, + vfloat4& rgbo_vector, + int plane2_component +) { + unsigned int weight_count = di.weight_count; + unsigned int total_texel_count = blk.texel_count; + + promise(total_texel_count > 0); + promise(weight_count > 0); + + alignas(ASTCENC_VECALIGN) float dec_weight_plane1[BLOCK_MAX_WEIGHTS_2PLANE]; + alignas(ASTCENC_VECALIGN) float dec_weight_plane2[BLOCK_MAX_WEIGHTS_2PLANE]; + + assert(weight_count <= BLOCK_MAX_WEIGHTS_2PLANE); + + for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + vint unquant_value1(dec_weights_uquant_plane1 + i); + vfloat unquant_value1f = int_to_float(unquant_value1) * vfloat(1.0f / 64.0f); + storea(unquant_value1f, dec_weight_plane1 + i); + + vint unquant_value2(dec_weights_uquant_plane2 + i); + vfloat unquant_value2f = int_to_float(unquant_value2) * vfloat(1.0f / 64.0f); + storea(unquant_value2f, dec_weight_plane2 + i); + } + + alignas(ASTCENC_VECALIGN) float undec_weight_plane1[BLOCK_MAX_TEXELS]; + alignas(ASTCENC_VECALIGN) float undec_weight_plane2[BLOCK_MAX_TEXELS]; + + float* undec_weight_plane1_ref; + float* undec_weight_plane2_ref; + + if (di.max_texel_weight_count == 1) + { + undec_weight_plane1_ref = dec_weight_plane1; + undec_weight_plane2_ref = dec_weight_plane2; + } + else if (di.max_texel_weight_count <= 2) + { + for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight = bilinear_infill_vla_2(di, dec_weight_plane1, i); + storea(weight, undec_weight_plane1 + i); + + weight = bilinear_infill_vla_2(di, dec_weight_plane2, i); + storea(weight, undec_weight_plane2 + i); + } + + undec_weight_plane1_ref = undec_weight_plane1; + undec_weight_plane2_ref = undec_weight_plane2; + } + else + { + for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH) + { + vfloat weight = bilinear_infill_vla(di, dec_weight_plane1, i); + storea(weight, undec_weight_plane1 + i); + + weight = bilinear_infill_vla(di, dec_weight_plane2, i); + storea(weight, undec_weight_plane2 + i); + } + + undec_weight_plane1_ref = undec_weight_plane1; + undec_weight_plane2_ref = undec_weight_plane2; + } + + unsigned int texel_count = bsd.texel_count; + vfloat4 rgba_weight_sum = max(blk.channel_weight * static_cast<float>(texel_count), 1e-17f); + vfloat4 scale_dir = normalize(blk.data_mean.swz<0, 1, 2>()); + + float scale_max = 0.0f; + float scale_min = 1e10f; + + float wmin1 = 1.0f; + float wmax1 = 0.0f; + + float wmin2 = 1.0f; + float wmax2 = 0.0f; + + float left1_sum_s = 0.0f; + float middle1_sum_s = 0.0f; + float right1_sum_s = 0.0f; + + float left2_sum_s = 0.0f; + float middle2_sum_s = 0.0f; + float right2_sum_s = 0.0f; + + vfloat4 color_vec_x = vfloat4::zero(); + vfloat4 color_vec_y = vfloat4::zero(); + + vfloat4 scale_vec = vfloat4::zero(); + + vfloat4 weight_weight_sum = vfloat4(1e-17f); + + vmask4 p2_mask = vint4::lane_id() == vint4(plane2_component); + vfloat4 color_weight = blk.channel_weight; + float ls_weight = hadd_rgb_s(color_weight); + + for (unsigned int j = 0; j < texel_count; j++) + { + vfloat4 rgba = blk.texel(j); + + float idx0 = undec_weight_plane1_ref[j]; + + float om_idx0 = 1.0f - idx0; + wmin1 = astc::min(idx0, wmin1); + wmax1 = astc::max(idx0, wmax1); + + float scale = dot3_s(scale_dir, rgba); + scale_min = astc::min(scale, scale_min); + scale_max = astc::max(scale, scale_max); + + left1_sum_s += om_idx0 * om_idx0; + middle1_sum_s += om_idx0 * idx0; + right1_sum_s += idx0 * idx0; + + float idx1 = undec_weight_plane2_ref[j]; + + float om_idx1 = 1.0f - idx1; + wmin2 = astc::min(idx1, wmin2); + wmax2 = astc::max(idx1, wmax2); + + left2_sum_s += om_idx1 * om_idx1; + middle2_sum_s += om_idx1 * idx1; + right2_sum_s += idx1 * idx1; + + vfloat4 color_idx = select(vfloat4(idx0), vfloat4(idx1), p2_mask); + + vfloat4 cwprod = rgba; + vfloat4 cwiprod = cwprod * color_idx; + + color_vec_y += cwiprod; + color_vec_x += cwprod - cwiprod; + + scale_vec += vfloat2(om_idx0, idx0) * (ls_weight * scale); + weight_weight_sum += color_idx; + } + + vfloat4 left1_sum = vfloat4(left1_sum_s) * color_weight; + vfloat4 middle1_sum = vfloat4(middle1_sum_s) * color_weight; + vfloat4 right1_sum = vfloat4(right1_sum_s) * color_weight; + vfloat4 lmrs_sum = vfloat3(left1_sum_s, middle1_sum_s, right1_sum_s) * ls_weight; + + vfloat4 left2_sum = vfloat4(left2_sum_s) * color_weight; + vfloat4 middle2_sum = vfloat4(middle2_sum_s) * color_weight; + vfloat4 right2_sum = vfloat4(right2_sum_s) * color_weight; + + color_vec_x = color_vec_x * color_weight; + color_vec_y = color_vec_y * color_weight; + + // Initialize the luminance and scale vectors with a reasonable default + float scalediv = scale_min / astc::max(scale_max, 1e-10f); + scalediv = astc::clamp1f(scalediv); + + vfloat4 sds = scale_dir * scale_max; + + rgbs_vector = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), scalediv); + + if (wmin1 >= wmax1 * 0.999f) + { + // If all weights in the partition were equal, then just take average of all colors in + // the partition and use that as both endpoint colors + vfloat4 avg = (color_vec_x + color_vec_y) / rgba_weight_sum; + + vmask4 p1_mask = vint4::lane_id() != vint4(plane2_component); + vmask4 notnan_mask = avg == avg; + vmask4 full_mask = p1_mask & notnan_mask; + + ep.endpt0[0] = select(ep.endpt0[0], avg, full_mask); + ep.endpt1[0] = select(ep.endpt1[0], avg, full_mask); + + rgbs_vector = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), 1.0f); + } + else + { + // Otherwise, complete the analytic calculation of ideal-endpoint-values for the given + // set of texel weights and pixel colors + vfloat4 color_det1 = (left1_sum * right1_sum) - (middle1_sum * middle1_sum); + vfloat4 color_rdet1 = 1.0f / color_det1; + + float ls_det1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<2>()) - (lmrs_sum.lane<1>() * lmrs_sum.lane<1>()); + float ls_rdet1 = 1.0f / ls_det1; + + vfloat4 color_mss1 = (left1_sum * left1_sum) + + (2.0f * middle1_sum * middle1_sum) + + (right1_sum * right1_sum); + + float ls_mss1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<0>()) + + (2.0f * lmrs_sum.lane<1>() * lmrs_sum.lane<1>()) + + (lmrs_sum.lane<2>() * lmrs_sum.lane<2>()); + + vfloat4 ep0 = (right1_sum * color_vec_x - middle1_sum * color_vec_y) * color_rdet1; + vfloat4 ep1 = (left1_sum * color_vec_y - middle1_sum * color_vec_x) * color_rdet1; + + float scale_ep0 = (lmrs_sum.lane<2>() * scale_vec.lane<0>() - lmrs_sum.lane<1>() * scale_vec.lane<1>()) * ls_rdet1; + float scale_ep1 = (lmrs_sum.lane<0>() * scale_vec.lane<1>() - lmrs_sum.lane<1>() * scale_vec.lane<0>()) * ls_rdet1; + + vmask4 p1_mask = vint4::lane_id() != vint4(plane2_component); + vmask4 det_mask = abs(color_det1) > (color_mss1 * 1e-4f); + vmask4 notnan_mask = (ep0 == ep0) & (ep1 == ep1); + vmask4 full_mask = p1_mask & det_mask & notnan_mask; + + ep.endpt0[0] = select(ep.endpt0[0], ep0, full_mask); + ep.endpt1[0] = select(ep.endpt1[0], ep1, full_mask); + + if (fabsf(ls_det1) > (ls_mss1 * 1e-4f) && scale_ep0 == scale_ep0 && scale_ep1 == scale_ep1 && scale_ep0 < scale_ep1) + { + float scalediv2 = scale_ep0 / scale_ep1; + vfloat4 sdsm = scale_dir * scale_ep1; + rgbs_vector = vfloat4(sdsm.lane<0>(), sdsm.lane<1>(), sdsm.lane<2>(), scalediv2); + } + } + + if (wmin2 >= wmax2 * 0.999f) + { + // If all weights in the partition were equal, then just take average of all colors in + // the partition and use that as both endpoint colors + vfloat4 avg = (color_vec_x + color_vec_y) / rgba_weight_sum; + + vmask4 notnan_mask = avg == avg; + vmask4 full_mask = p2_mask & notnan_mask; + + ep.endpt0[0] = select(ep.endpt0[0], avg, full_mask); + ep.endpt1[0] = select(ep.endpt1[0], avg, full_mask); + } + else + { + // Otherwise, complete the analytic calculation of ideal-endpoint-values for the given + // set of texel weights and pixel colors + vfloat4 color_det2 = (left2_sum * right2_sum) - (middle2_sum * middle2_sum); + vfloat4 color_rdet2 = 1.0f / color_det2; + + vfloat4 color_mss2 = (left2_sum * left2_sum) + + (2.0f * middle2_sum * middle2_sum) + + (right2_sum * right2_sum); + + vfloat4 ep0 = (right2_sum * color_vec_x - middle2_sum * color_vec_y) * color_rdet2; + vfloat4 ep1 = (left2_sum * color_vec_y - middle2_sum * color_vec_x) * color_rdet2; + + vmask4 det_mask = abs(color_det2) > (color_mss2 * 1e-4f); + vmask4 notnan_mask = (ep0 == ep0) & (ep1 == ep1); + vmask4 full_mask = p2_mask & det_mask & notnan_mask; + + ep.endpt0[0] = select(ep.endpt0[0], ep0, full_mask); + ep.endpt1[0] = select(ep.endpt1[0], ep1, full_mask); + } + + // Calculations specific to mode #7, the HDR RGB-scale mode - skip if known LDR + if (blk.rgb_lns[0] || blk.alpha_lns[0]) + { + weight_weight_sum = weight_weight_sum * color_weight; + float psum = dot3_s(select(right1_sum, right2_sum, p2_mask), color_weight); + + vfloat4 rgbq_sum = color_vec_x + color_vec_y; + rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y)); + + rgbo_vector = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum); + + // We can get a failure due to the use of a singular (non-invertible) matrix + // If it failed, compute rgbo_vectors[] with a different method ... + if (astc::isnan(dot_s(rgbo_vector, rgbo_vector))) + { + vfloat4 v0 = ep.endpt0[0]; + vfloat4 v1 = ep.endpt1[0]; + + float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f); + avgdif = astc::max(avgdif, 0.0f); + + vfloat4 avg = (v0 + v1) * 0.5f; + vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f; + + rgbo_vector = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif); + } + } +} + +#endif diff --git a/thirdparty/astcenc/astcenc_image.cpp b/thirdparty/astcenc/astcenc_image.cpp new file mode 100644 index 0000000000..9c0d6727d0 --- /dev/null +++ b/thirdparty/astcenc/astcenc_image.cpp @@ -0,0 +1,558 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for creating in-memory ASTC image structures. + */ + +#include <cassert> +#include <cstring> + +#include "astcenc_internal.h" + +/** + * @brief Loader pipeline function type for data fetch from memory. + */ +using pixel_loader = vfloat4(*)(const void*, int); + +/** + * @brief Loader pipeline function type for swizzling data in a vector. + */ +using pixel_swizzler = vfloat4(*)(vfloat4, const astcenc_swizzle&); + +/** + * @brief Loader pipeline function type for converting data in a vector to LNS. + */ +using pixel_converter = vfloat4(*)(vfloat4, vmask4); + +/** + * @brief Load a 8-bit UNORM texel from a data array. + * + * @param data The data pointer. + * @param base_offset The index offset to the start of the pixel. + */ +static vfloat4 load_texel_u8( + const void* data, + int base_offset +) { + const uint8_t* data8 = static_cast<const uint8_t*>(data); + return int_to_float(vint4(data8 + base_offset)) / 255.0f; +} + +/** + * @brief Load a 16-bit fp16 texel from a data array. + * + * @param data The data pointer. + * @param base_offset The index offset to the start of the pixel. + */ +static vfloat4 load_texel_f16( + const void* data, + int base_offset +) { + const uint16_t* data16 = static_cast<const uint16_t*>(data); + int r = data16[base_offset ]; + int g = data16[base_offset + 1]; + int b = data16[base_offset + 2]; + int a = data16[base_offset + 3]; + return float16_to_float(vint4(r, g, b, a)); +} + +/** + * @brief Load a 32-bit float texel from a data array. + * + * @param data The data pointer. + * @param base_offset The index offset to the start of the pixel. + */ +static vfloat4 load_texel_f32( + const void* data, + int base_offset +) { + const float* data32 = static_cast<const float*>(data); + return vfloat4(data32 + base_offset); +} + +/** + * @brief Dummy no-op swizzle function. + * + * @param data The source RGBA vector to swizzle. + * @param swz The swizzle to use. + */ +static vfloat4 swz_texel_skip( + vfloat4 data, + const astcenc_swizzle& swz +) { + (void)swz; + return data; +} + +/** + * @brief Swizzle a texel into a new arrangement. + * + * @param data The source RGBA vector to swizzle. + * @param swz The swizzle to use. + */ +static vfloat4 swz_texel( + vfloat4 data, + const astcenc_swizzle& swz +) { + alignas(16) float datas[6]; + + storea(data, datas); + datas[ASTCENC_SWZ_0] = 0.0f; + datas[ASTCENC_SWZ_1] = 1.0f; + + return vfloat4(datas[swz.r], datas[swz.g], datas[swz.b], datas[swz.a]); +} + +/** + * @brief Encode a texel that is entirely LDR linear. + * + * @param data The RGBA data to encode. + * @param lns_mask The mask for the HDR channels than need LNS encoding. + */ +static vfloat4 encode_texel_unorm( + vfloat4 data, + vmask4 lns_mask +) { + (void)lns_mask; + return data * 65535.0f; +} + +/** + * @brief Encode a texel that includes at least some HDR LNS texels. + * + * @param data The RGBA data to encode. + * @param lns_mask The mask for the HDR channels than need LNS encoding. + */ +static vfloat4 encode_texel_lns( + vfloat4 data, + vmask4 lns_mask +) { + vfloat4 datav_unorm = data * 65535.0f; + vfloat4 datav_lns = float_to_lns(data); + return select(datav_unorm, datav_lns, lns_mask); +} + +/* See header for documentation. */ +void load_image_block( + astcenc_profile decode_mode, + const astcenc_image& img, + image_block& blk, + const block_size_descriptor& bsd, + unsigned int xpos, + unsigned int ypos, + unsigned int zpos, + const astcenc_swizzle& swz +) { + unsigned int xsize = img.dim_x; + unsigned int ysize = img.dim_y; + unsigned int zsize = img.dim_z; + + blk.xpos = xpos; + blk.ypos = ypos; + blk.zpos = zpos; + + // True if any non-identity swizzle + bool needs_swz = (swz.r != ASTCENC_SWZ_R) || (swz.g != ASTCENC_SWZ_G) || + (swz.b != ASTCENC_SWZ_B) || (swz.a != ASTCENC_SWZ_A); + + int idx = 0; + + vfloat4 data_min(1e38f); + vfloat4 data_mean(0.0f); + vfloat4 data_mean_scale(1.0f / static_cast<float>(bsd.texel_count)); + vfloat4 data_max(-1e38f); + vmask4 grayscalev(true); + + // This works because we impose the same choice everywhere during encode + uint8_t rgb_lns = (decode_mode == ASTCENC_PRF_HDR) || + (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A) ? 1 : 0; + uint8_t a_lns = decode_mode == ASTCENC_PRF_HDR ? 1 : 0; + vint4 use_lns(rgb_lns, rgb_lns, rgb_lns, a_lns); + vmask4 lns_mask = use_lns != vint4::zero(); + + // Set up the function pointers for loading pipeline as needed + pixel_loader loader = load_texel_u8; + if (img.data_type == ASTCENC_TYPE_F16) + { + loader = load_texel_f16; + } + else if (img.data_type == ASTCENC_TYPE_F32) + { + loader = load_texel_f32; + } + + pixel_swizzler swizzler = swz_texel_skip; + if (needs_swz) + { + swizzler = swz_texel; + } + + pixel_converter converter = encode_texel_unorm; + if (any(lns_mask)) + { + converter = encode_texel_lns; + } + + for (unsigned int z = 0; z < bsd.zdim; z++) + { + unsigned int zi = astc::min(zpos + z, zsize - 1); + void* plane = img.data[zi]; + + for (unsigned int y = 0; y < bsd.ydim; y++) + { + unsigned int yi = astc::min(ypos + y, ysize - 1); + + for (unsigned int x = 0; x < bsd.xdim; x++) + { + unsigned int xi = astc::min(xpos + x, xsize - 1); + + vfloat4 datav = loader(plane, (4 * xsize * yi) + (4 * xi)); + datav = swizzler(datav, swz); + datav = converter(datav, lns_mask); + + // Compute block metadata + data_min = min(data_min, datav); + data_mean += datav * data_mean_scale; + data_max = max(data_max, datav); + + grayscalev = grayscalev & (datav.swz<0,0,0,0>() == datav.swz<1,1,2,2>()); + + blk.data_r[idx] = datav.lane<0>(); + blk.data_g[idx] = datav.lane<1>(); + blk.data_b[idx] = datav.lane<2>(); + blk.data_a[idx] = datav.lane<3>(); + + blk.rgb_lns[idx] = rgb_lns; + blk.alpha_lns[idx] = a_lns; + + idx++; + } + } + } + + // Reverse the encoding so we store origin block in the original format + vfloat4 data_enc = blk.texel(0); + vfloat4 data_enc_unorm = data_enc / 65535.0f; + vfloat4 data_enc_lns = vfloat4::zero(); + + if (rgb_lns || a_lns) + { + data_enc_lns = float16_to_float(lns_to_sf16(float_to_int(data_enc))); + } + + blk.origin_texel = select(data_enc_unorm, data_enc_lns, lns_mask); + + // Store block metadata + blk.data_min = data_min; + blk.data_mean = data_mean; + blk.data_max = data_max; + blk.grayscale = all(grayscalev); +} + +/* See header for documentation. */ +void load_image_block_fast_ldr( + astcenc_profile decode_mode, + const astcenc_image& img, + image_block& blk, + const block_size_descriptor& bsd, + unsigned int xpos, + unsigned int ypos, + unsigned int zpos, + const astcenc_swizzle& swz +) { + (void)swz; + (void)decode_mode; + + unsigned int xsize = img.dim_x; + unsigned int ysize = img.dim_y; + + blk.xpos = xpos; + blk.ypos = ypos; + blk.zpos = zpos; + + vfloat4 data_min(1e38f); + vfloat4 data_mean = vfloat4::zero(); + vfloat4 data_max(-1e38f); + vmask4 grayscalev(true); + int idx = 0; + + const uint8_t* plane = static_cast<const uint8_t*>(img.data[0]); + for (unsigned int y = ypos; y < ypos + bsd.ydim; y++) + { + unsigned int yi = astc::min(y, ysize - 1); + + for (unsigned int x = xpos; x < xpos + bsd.xdim; x++) + { + unsigned int xi = astc::min(x, xsize - 1); + + vint4 datavi = vint4(plane + (4 * xsize * yi) + (4 * xi)); + vfloat4 datav = int_to_float(datavi) * (65535.0f / 255.0f); + + // Compute block metadata + data_min = min(data_min, datav); + data_mean += datav; + data_max = max(data_max, datav); + + grayscalev = grayscalev & (datav.swz<0,0,0,0>() == datav.swz<1,1,2,2>()); + + blk.data_r[idx] = datav.lane<0>(); + blk.data_g[idx] = datav.lane<1>(); + blk.data_b[idx] = datav.lane<2>(); + blk.data_a[idx] = datav.lane<3>(); + + idx++; + } + } + + // Reverse the encoding so we store origin block in the original format + blk.origin_texel = blk.texel(0) / 65535.0f; + + // Store block metadata + blk.rgb_lns[0] = 0; + blk.alpha_lns[0] = 0; + blk.data_min = data_min; + blk.data_mean = data_mean / static_cast<float>(bsd.texel_count); + blk.data_max = data_max; + blk.grayscale = all(grayscalev); +} + +/* See header for documentation. */ +void store_image_block( + astcenc_image& img, + const image_block& blk, + const block_size_descriptor& bsd, + unsigned int xpos, + unsigned int ypos, + unsigned int zpos, + const astcenc_swizzle& swz +) { + unsigned int x_size = img.dim_x; + unsigned int x_start = xpos; + unsigned int x_end = astc::min(x_size, xpos + bsd.xdim); + unsigned int x_count = x_end - x_start; + unsigned int x_nudge = bsd.xdim - x_count; + + unsigned int y_size = img.dim_y; + unsigned int y_start = ypos; + unsigned int y_end = astc::min(y_size, ypos + bsd.ydim); + unsigned int y_count = y_end - y_start; + unsigned int y_nudge = (bsd.ydim - y_count) * bsd.xdim; + + unsigned int z_size = img.dim_z; + unsigned int z_start = zpos; + unsigned int z_end = astc::min(z_size, zpos + bsd.zdim); + + // True if any non-identity swizzle + bool needs_swz = (swz.r != ASTCENC_SWZ_R) || (swz.g != ASTCENC_SWZ_G) || + (swz.b != ASTCENC_SWZ_B) || (swz.a != ASTCENC_SWZ_A); + + // True if any swizzle uses Z reconstruct + bool needs_z = (swz.r == ASTCENC_SWZ_Z) || (swz.g == ASTCENC_SWZ_Z) || + (swz.b == ASTCENC_SWZ_Z) || (swz.a == ASTCENC_SWZ_Z); + + int idx = 0; + if (img.data_type == ASTCENC_TYPE_U8) + { + for (unsigned int z = z_start; z < z_end; z++) + { + // Fetch the image plane + uint8_t* data8 = static_cast<uint8_t*>(img.data[z]); + + for (unsigned int y = y_start; y < y_end; y++) + { + uint8_t* data8_row = data8 + (4 * x_size * y) + (4 * x_start); + + for (unsigned int x = 0; x < x_count; x += ASTCENC_SIMD_WIDTH) + { + unsigned int max_texels = ASTCENC_SIMD_WIDTH; + unsigned int used_texels = astc::min(x_count - x, max_texels); + + // Unaligned load as rows are not always SIMD_WIDTH long + vfloat data_r(blk.data_r + idx); + vfloat data_g(blk.data_g + idx); + vfloat data_b(blk.data_b + idx); + vfloat data_a(blk.data_a + idx); + + vint data_ri = float_to_int_rtn(min(data_r, 1.0f) * 255.0f); + vint data_gi = float_to_int_rtn(min(data_g, 1.0f) * 255.0f); + vint data_bi = float_to_int_rtn(min(data_b, 1.0f) * 255.0f); + vint data_ai = float_to_int_rtn(min(data_a, 1.0f) * 255.0f); + + if (needs_swz) + { + vint swizzle_table[7]; + swizzle_table[ASTCENC_SWZ_0] = vint(0); + swizzle_table[ASTCENC_SWZ_1] = vint(255); + swizzle_table[ASTCENC_SWZ_R] = data_ri; + swizzle_table[ASTCENC_SWZ_G] = data_gi; + swizzle_table[ASTCENC_SWZ_B] = data_bi; + swizzle_table[ASTCENC_SWZ_A] = data_ai; + + if (needs_z) + { + vfloat data_x = (data_r * vfloat(2.0f)) - vfloat(1.0f); + vfloat data_y = (data_a * vfloat(2.0f)) - vfloat(1.0f); + vfloat data_z = vfloat(1.0f) - (data_x * data_x) - (data_y * data_y); + data_z = max(data_z, 0.0f); + data_z = (sqrt(data_z) * vfloat(0.5f)) + vfloat(0.5f); + + swizzle_table[ASTCENC_SWZ_Z] = float_to_int_rtn(min(data_z, 1.0f) * 255.0f); + } + + data_ri = swizzle_table[swz.r]; + data_gi = swizzle_table[swz.g]; + data_bi = swizzle_table[swz.b]; + data_ai = swizzle_table[swz.a]; + } + + // Errors are NaN encoded - convert to magenta error color + // Branch is OK here - it is almost never true so predicts well + vmask nan_mask = data_r != data_r; + if (any(nan_mask)) + { + data_ri = select(data_ri, vint(0xFF), nan_mask); + data_gi = select(data_gi, vint(0x00), nan_mask); + data_bi = select(data_bi, vint(0xFF), nan_mask); + data_ai = select(data_ai, vint(0xFF), nan_mask); + } + + vint data_rgbai = interleave_rgba8(data_ri, data_gi, data_bi, data_ai); + vmask store_mask = vint::lane_id() < vint(used_texels); + store_lanes_masked(reinterpret_cast<int*>(data8_row), data_rgbai, store_mask); + + data8_row += ASTCENC_SIMD_WIDTH * 4; + idx += used_texels; + } + idx += x_nudge; + } + idx += y_nudge; + } + } + else if (img.data_type == ASTCENC_TYPE_F16) + { + for (unsigned int z = z_start; z < z_end; z++) + { + // Fetch the image plane + uint16_t* data16 = static_cast<uint16_t*>(img.data[z]); + + for (unsigned int y = y_start; y < y_end; y++) + { + uint16_t* data16_row = data16 + (4 * x_size * y) + (4 * x_start); + + for (unsigned int x = 0; x < x_count; x++) + { + vint4 color; + + // NaNs are handled inline - no need to special case + if (needs_swz) + { + float data[7]; + data[ASTCENC_SWZ_0] = 0.0f; + data[ASTCENC_SWZ_1] = 1.0f; + data[ASTCENC_SWZ_R] = blk.data_r[idx]; + data[ASTCENC_SWZ_G] = blk.data_g[idx]; + data[ASTCENC_SWZ_B] = blk.data_b[idx]; + data[ASTCENC_SWZ_A] = blk.data_a[idx]; + + if (needs_z) + { + float xN = (data[0] * 2.0f) - 1.0f; + float yN = (data[3] * 2.0f) - 1.0f; + float zN = 1.0f - xN * xN - yN * yN; + if (zN < 0.0f) + { + zN = 0.0f; + } + data[ASTCENC_SWZ_Z] = (astc::sqrt(zN) * 0.5f) + 0.5f; + } + + vfloat4 colorf(data[swz.r], data[swz.g], data[swz.b], data[swz.a]); + color = float_to_float16(colorf); + } + else + { + vfloat4 colorf = blk.texel(idx); + color = float_to_float16(colorf); + } + + // TODO: Vectorize with store N shorts? + data16_row[0] = static_cast<uint16_t>(color.lane<0>()); + data16_row[1] = static_cast<uint16_t>(color.lane<1>()); + data16_row[2] = static_cast<uint16_t>(color.lane<2>()); + data16_row[3] = static_cast<uint16_t>(color.lane<3>()); + data16_row += 4; + idx++; + } + idx += x_nudge; + } + idx += y_nudge; + } + } + else // if (img.data_type == ASTCENC_TYPE_F32) + { + assert(img.data_type == ASTCENC_TYPE_F32); + + for (unsigned int z = z_start; z < z_end; z++) + { + // Fetch the image plane + float* data32 = static_cast<float*>(img.data[z]); + + for (unsigned int y = y_start; y < y_end; y++) + { + float* data32_row = data32 + (4 * x_size * y) + (4 * x_start); + + for (unsigned int x = 0; x < x_count; x++) + { + vfloat4 color = blk.texel(idx); + + // NaNs are handled inline - no need to special case + if (needs_swz) + { + float data[7]; + data[ASTCENC_SWZ_0] = 0.0f; + data[ASTCENC_SWZ_1] = 1.0f; + data[ASTCENC_SWZ_R] = color.lane<0>(); + data[ASTCENC_SWZ_G] = color.lane<1>(); + data[ASTCENC_SWZ_B] = color.lane<2>(); + data[ASTCENC_SWZ_A] = color.lane<3>(); + + if (needs_z) + { + float xN = (data[0] * 2.0f) - 1.0f; + float yN = (data[3] * 2.0f) - 1.0f; + float zN = 1.0f - xN * xN - yN * yN; + if (zN < 0.0f) + { + zN = 0.0f; + } + data[ASTCENC_SWZ_Z] = (astc::sqrt(zN) * 0.5f) + 0.5f; + } + + color = vfloat4(data[swz.r], data[swz.g], data[swz.b], data[swz.a]); + } + + store(color, data32_row); + data32_row += 4; + idx++; + } + idx += x_nudge; + } + idx += y_nudge; + } + } +} diff --git a/thirdparty/astcenc/astcenc_integer_sequence.cpp b/thirdparty/astcenc/astcenc_integer_sequence.cpp new file mode 100644 index 0000000000..416750374d --- /dev/null +++ b/thirdparty/astcenc/astcenc_integer_sequence.cpp @@ -0,0 +1,739 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for encoding/decoding Bounded Integer Sequence Encoding. + */ + +#include "astcenc_internal.h" + +#include <array> + +/** @brief Unpacked quint triplets <low,middle,high> for each packed value */ +// TODO: Bitpack these into a uint16_t? +static const uint8_t quints_of_integer[128][3] { + {0, 0, 0}, {1, 0, 0}, {2, 0, 0}, {3, 0, 0}, + {4, 0, 0}, {0, 4, 0}, {4, 4, 0}, {4, 4, 4}, + {0, 1, 0}, {1, 1, 0}, {2, 1, 0}, {3, 1, 0}, + {4, 1, 0}, {1, 4, 0}, {4, 4, 1}, {4, 4, 4}, + {0, 2, 0}, {1, 2, 0}, {2, 2, 0}, {3, 2, 0}, + {4, 2, 0}, {2, 4, 0}, {4, 4, 2}, {4, 4, 4}, + {0, 3, 0}, {1, 3, 0}, {2, 3, 0}, {3, 3, 0}, + {4, 3, 0}, {3, 4, 0}, {4, 4, 3}, {4, 4, 4}, + {0, 0, 1}, {1, 0, 1}, {2, 0, 1}, {3, 0, 1}, + {4, 0, 1}, {0, 4, 1}, {4, 0, 4}, {0, 4, 4}, + {0, 1, 1}, {1, 1, 1}, {2, 1, 1}, {3, 1, 1}, + {4, 1, 1}, {1, 4, 1}, {4, 1, 4}, {1, 4, 4}, + {0, 2, 1}, {1, 2, 1}, {2, 2, 1}, {3, 2, 1}, + {4, 2, 1}, {2, 4, 1}, {4, 2, 4}, {2, 4, 4}, + {0, 3, 1}, {1, 3, 1}, {2, 3, 1}, {3, 3, 1}, + {4, 3, 1}, {3, 4, 1}, {4, 3, 4}, {3, 4, 4}, + {0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {3, 0, 2}, + {4, 0, 2}, {0, 4, 2}, {2, 0, 4}, {3, 0, 4}, + {0, 1, 2}, {1, 1, 2}, {2, 1, 2}, {3, 1, 2}, + {4, 1, 2}, {1, 4, 2}, {2, 1, 4}, {3, 1, 4}, + {0, 2, 2}, {1, 2, 2}, {2, 2, 2}, {3, 2, 2}, + {4, 2, 2}, {2, 4, 2}, {2, 2, 4}, {3, 2, 4}, + {0, 3, 2}, {1, 3, 2}, {2, 3, 2}, {3, 3, 2}, + {4, 3, 2}, {3, 4, 2}, {2, 3, 4}, {3, 3, 4}, + {0, 0, 3}, {1, 0, 3}, {2, 0, 3}, {3, 0, 3}, + {4, 0, 3}, {0, 4, 3}, {0, 0, 4}, {1, 0, 4}, + {0, 1, 3}, {1, 1, 3}, {2, 1, 3}, {3, 1, 3}, + {4, 1, 3}, {1, 4, 3}, {0, 1, 4}, {1, 1, 4}, + {0, 2, 3}, {1, 2, 3}, {2, 2, 3}, {3, 2, 3}, + {4, 2, 3}, {2, 4, 3}, {0, 2, 4}, {1, 2, 4}, + {0, 3, 3}, {1, 3, 3}, {2, 3, 3}, {3, 3, 3}, + {4, 3, 3}, {3, 4, 3}, {0, 3, 4}, {1, 3, 4} +}; + +/** @brief Packed quint values for each unpacked value, indexed [hi][mid][lo]. */ +static const uint8_t integer_of_quints[5][5][5] { + { + {0, 1, 2, 3, 4}, + {8, 9, 10, 11, 12}, + {16, 17, 18, 19, 20}, + {24, 25, 26, 27, 28}, + {5, 13, 21, 29, 6} + }, + { + {32, 33, 34, 35, 36}, + {40, 41, 42, 43, 44}, + {48, 49, 50, 51, 52}, + {56, 57, 58, 59, 60}, + {37, 45, 53, 61, 14} + }, + { + {64, 65, 66, 67, 68}, + {72, 73, 74, 75, 76}, + {80, 81, 82, 83, 84}, + {88, 89, 90, 91, 92}, + {69, 77, 85, 93, 22} + }, + { + {96, 97, 98, 99, 100}, + {104, 105, 106, 107, 108}, + {112, 113, 114, 115, 116}, + {120, 121, 122, 123, 124}, + {101, 109, 117, 125, 30} + }, + { + {102, 103, 70, 71, 38}, + {110, 111, 78, 79, 46}, + {118, 119, 86, 87, 54}, + {126, 127, 94, 95, 62}, + {39, 47, 55, 63, 31} + } +}; + +/** @brief Unpacked trit quintuplets <low,...,high> for each packed value */ +// TODO: Bitpack these into a uint16_t? +static const uint8_t trits_of_integer[256][5] { + {0, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {2, 0, 0, 0, 0}, {0, 0, 2, 0, 0}, + {0, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {2, 1, 0, 0, 0}, {1, 0, 2, 0, 0}, + {0, 2, 0, 0, 0}, {1, 2, 0, 0, 0}, {2, 2, 0, 0, 0}, {2, 0, 2, 0, 0}, + {0, 2, 2, 0, 0}, {1, 2, 2, 0, 0}, {2, 2, 2, 0, 0}, {2, 0, 2, 0, 0}, + {0, 0, 1, 0, 0}, {1, 0, 1, 0, 0}, {2, 0, 1, 0, 0}, {0, 1, 2, 0, 0}, + {0, 1, 1, 0, 0}, {1, 1, 1, 0, 0}, {2, 1, 1, 0, 0}, {1, 1, 2, 0, 0}, + {0, 2, 1, 0, 0}, {1, 2, 1, 0, 0}, {2, 2, 1, 0, 0}, {2, 1, 2, 0, 0}, + {0, 0, 0, 2, 2}, {1, 0, 0, 2, 2}, {2, 0, 0, 2, 2}, {0, 0, 2, 2, 2}, + {0, 0, 0, 1, 0}, {1, 0, 0, 1, 0}, {2, 0, 0, 1, 0}, {0, 0, 2, 1, 0}, + {0, 1, 0, 1, 0}, {1, 1, 0, 1, 0}, {2, 1, 0, 1, 0}, {1, 0, 2, 1, 0}, + {0, 2, 0, 1, 0}, {1, 2, 0, 1, 0}, {2, 2, 0, 1, 0}, {2, 0, 2, 1, 0}, + {0, 2, 2, 1, 0}, {1, 2, 2, 1, 0}, {2, 2, 2, 1, 0}, {2, 0, 2, 1, 0}, + {0, 0, 1, 1, 0}, {1, 0, 1, 1, 0}, {2, 0, 1, 1, 0}, {0, 1, 2, 1, 0}, + {0, 1, 1, 1, 0}, {1, 1, 1, 1, 0}, {2, 1, 1, 1, 0}, {1, 1, 2, 1, 0}, + {0, 2, 1, 1, 0}, {1, 2, 1, 1, 0}, {2, 2, 1, 1, 0}, {2, 1, 2, 1, 0}, + {0, 1, 0, 2, 2}, {1, 1, 0, 2, 2}, {2, 1, 0, 2, 2}, {1, 0, 2, 2, 2}, + {0, 0, 0, 2, 0}, {1, 0, 0, 2, 0}, {2, 0, 0, 2, 0}, {0, 0, 2, 2, 0}, + {0, 1, 0, 2, 0}, {1, 1, 0, 2, 0}, {2, 1, 0, 2, 0}, {1, 0, 2, 2, 0}, + {0, 2, 0, 2, 0}, {1, 2, 0, 2, 0}, {2, 2, 0, 2, 0}, {2, 0, 2, 2, 0}, + {0, 2, 2, 2, 0}, {1, 2, 2, 2, 0}, {2, 2, 2, 2, 0}, {2, 0, 2, 2, 0}, + {0, 0, 1, 2, 0}, {1, 0, 1, 2, 0}, {2, 0, 1, 2, 0}, {0, 1, 2, 2, 0}, + {0, 1, 1, 2, 0}, {1, 1, 1, 2, 0}, {2, 1, 1, 2, 0}, {1, 1, 2, 2, 0}, + {0, 2, 1, 2, 0}, {1, 2, 1, 2, 0}, {2, 2, 1, 2, 0}, {2, 1, 2, 2, 0}, + {0, 2, 0, 2, 2}, {1, 2, 0, 2, 2}, {2, 2, 0, 2, 2}, {2, 0, 2, 2, 2}, + {0, 0, 0, 0, 2}, {1, 0, 0, 0, 2}, {2, 0, 0, 0, 2}, {0, 0, 2, 0, 2}, + {0, 1, 0, 0, 2}, {1, 1, 0, 0, 2}, {2, 1, 0, 0, 2}, {1, 0, 2, 0, 2}, + {0, 2, 0, 0, 2}, {1, 2, 0, 0, 2}, {2, 2, 0, 0, 2}, {2, 0, 2, 0, 2}, + {0, 2, 2, 0, 2}, {1, 2, 2, 0, 2}, {2, 2, 2, 0, 2}, {2, 0, 2, 0, 2}, + {0, 0, 1, 0, 2}, {1, 0, 1, 0, 2}, {2, 0, 1, 0, 2}, {0, 1, 2, 0, 2}, + {0, 1, 1, 0, 2}, {1, 1, 1, 0, 2}, {2, 1, 1, 0, 2}, {1, 1, 2, 0, 2}, + {0, 2, 1, 0, 2}, {1, 2, 1, 0, 2}, {2, 2, 1, 0, 2}, {2, 1, 2, 0, 2}, + {0, 2, 2, 2, 2}, {1, 2, 2, 2, 2}, {2, 2, 2, 2, 2}, {2, 0, 2, 2, 2}, + {0, 0, 0, 0, 1}, {1, 0, 0, 0, 1}, {2, 0, 0, 0, 1}, {0, 0, 2, 0, 1}, + {0, 1, 0, 0, 1}, {1, 1, 0, 0, 1}, {2, 1, 0, 0, 1}, {1, 0, 2, 0, 1}, + {0, 2, 0, 0, 1}, {1, 2, 0, 0, 1}, {2, 2, 0, 0, 1}, {2, 0, 2, 0, 1}, + {0, 2, 2, 0, 1}, {1, 2, 2, 0, 1}, {2, 2, 2, 0, 1}, {2, 0, 2, 0, 1}, + {0, 0, 1, 0, 1}, {1, 0, 1, 0, 1}, {2, 0, 1, 0, 1}, {0, 1, 2, 0, 1}, + {0, 1, 1, 0, 1}, {1, 1, 1, 0, 1}, {2, 1, 1, 0, 1}, {1, 1, 2, 0, 1}, + {0, 2, 1, 0, 1}, {1, 2, 1, 0, 1}, {2, 2, 1, 0, 1}, {2, 1, 2, 0, 1}, + {0, 0, 1, 2, 2}, {1, 0, 1, 2, 2}, {2, 0, 1, 2, 2}, {0, 1, 2, 2, 2}, + {0, 0, 0, 1, 1}, {1, 0, 0, 1, 1}, {2, 0, 0, 1, 1}, {0, 0, 2, 1, 1}, + {0, 1, 0, 1, 1}, {1, 1, 0, 1, 1}, {2, 1, 0, 1, 1}, {1, 0, 2, 1, 1}, + {0, 2, 0, 1, 1}, {1, 2, 0, 1, 1}, {2, 2, 0, 1, 1}, {2, 0, 2, 1, 1}, + {0, 2, 2, 1, 1}, {1, 2, 2, 1, 1}, {2, 2, 2, 1, 1}, {2, 0, 2, 1, 1}, + {0, 0, 1, 1, 1}, {1, 0, 1, 1, 1}, {2, 0, 1, 1, 1}, {0, 1, 2, 1, 1}, + {0, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {2, 1, 1, 1, 1}, {1, 1, 2, 1, 1}, + {0, 2, 1, 1, 1}, {1, 2, 1, 1, 1}, {2, 2, 1, 1, 1}, {2, 1, 2, 1, 1}, + {0, 1, 1, 2, 2}, {1, 1, 1, 2, 2}, {2, 1, 1, 2, 2}, {1, 1, 2, 2, 2}, + {0, 0, 0, 2, 1}, {1, 0, 0, 2, 1}, {2, 0, 0, 2, 1}, {0, 0, 2, 2, 1}, + {0, 1, 0, 2, 1}, {1, 1, 0, 2, 1}, {2, 1, 0, 2, 1}, {1, 0, 2, 2, 1}, + {0, 2, 0, 2, 1}, {1, 2, 0, 2, 1}, {2, 2, 0, 2, 1}, {2, 0, 2, 2, 1}, + {0, 2, 2, 2, 1}, {1, 2, 2, 2, 1}, {2, 2, 2, 2, 1}, {2, 0, 2, 2, 1}, + {0, 0, 1, 2, 1}, {1, 0, 1, 2, 1}, {2, 0, 1, 2, 1}, {0, 1, 2, 2, 1}, + {0, 1, 1, 2, 1}, {1, 1, 1, 2, 1}, {2, 1, 1, 2, 1}, {1, 1, 2, 2, 1}, + {0, 2, 1, 2, 1}, {1, 2, 1, 2, 1}, {2, 2, 1, 2, 1}, {2, 1, 2, 2, 1}, + {0, 2, 1, 2, 2}, {1, 2, 1, 2, 2}, {2, 2, 1, 2, 2}, {2, 1, 2, 2, 2}, + {0, 0, 0, 1, 2}, {1, 0, 0, 1, 2}, {2, 0, 0, 1, 2}, {0, 0, 2, 1, 2}, + {0, 1, 0, 1, 2}, {1, 1, 0, 1, 2}, {2, 1, 0, 1, 2}, {1, 0, 2, 1, 2}, + {0, 2, 0, 1, 2}, {1, 2, 0, 1, 2}, {2, 2, 0, 1, 2}, {2, 0, 2, 1, 2}, + {0, 2, 2, 1, 2}, {1, 2, 2, 1, 2}, {2, 2, 2, 1, 2}, {2, 0, 2, 1, 2}, + {0, 0, 1, 1, 2}, {1, 0, 1, 1, 2}, {2, 0, 1, 1, 2}, {0, 1, 2, 1, 2}, + {0, 1, 1, 1, 2}, {1, 1, 1, 1, 2}, {2, 1, 1, 1, 2}, {1, 1, 2, 1, 2}, + {0, 2, 1, 1, 2}, {1, 2, 1, 1, 2}, {2, 2, 1, 1, 2}, {2, 1, 2, 1, 2}, + {0, 2, 2, 2, 2}, {1, 2, 2, 2, 2}, {2, 2, 2, 2, 2}, {2, 1, 2, 2, 2} +}; + +/** @brief Packed trit values for each unpacked value, indexed [hi][][][][lo]. */ +static const uint8_t integer_of_trits[3][3][3][3][3] { + { + { + { + {0, 1, 2}, + {4, 5, 6}, + {8, 9, 10} + }, + { + {16, 17, 18}, + {20, 21, 22}, + {24, 25, 26} + }, + { + {3, 7, 15}, + {19, 23, 27}, + {12, 13, 14} + } + }, + { + { + {32, 33, 34}, + {36, 37, 38}, + {40, 41, 42} + }, + { + {48, 49, 50}, + {52, 53, 54}, + {56, 57, 58} + }, + { + {35, 39, 47}, + {51, 55, 59}, + {44, 45, 46} + } + }, + { + { + {64, 65, 66}, + {68, 69, 70}, + {72, 73, 74} + }, + { + {80, 81, 82}, + {84, 85, 86}, + {88, 89, 90} + }, + { + {67, 71, 79}, + {83, 87, 91}, + {76, 77, 78} + } + } + }, + { + { + { + {128, 129, 130}, + {132, 133, 134}, + {136, 137, 138} + }, + { + {144, 145, 146}, + {148, 149, 150}, + {152, 153, 154} + }, + { + {131, 135, 143}, + {147, 151, 155}, + {140, 141, 142} + } + }, + { + { + {160, 161, 162}, + {164, 165, 166}, + {168, 169, 170} + }, + { + {176, 177, 178}, + {180, 181, 182}, + {184, 185, 186} + }, + { + {163, 167, 175}, + {179, 183, 187}, + {172, 173, 174} + } + }, + { + { + {192, 193, 194}, + {196, 197, 198}, + {200, 201, 202} + }, + { + {208, 209, 210}, + {212, 213, 214}, + {216, 217, 218} + }, + { + {195, 199, 207}, + {211, 215, 219}, + {204, 205, 206} + } + } + }, + { + { + { + {96, 97, 98}, + {100, 101, 102}, + {104, 105, 106} + }, + { + {112, 113, 114}, + {116, 117, 118}, + {120, 121, 122} + }, + { + {99, 103, 111}, + {115, 119, 123}, + {108, 109, 110} + } + }, + { + { + {224, 225, 226}, + {228, 229, 230}, + {232, 233, 234} + }, + { + {240, 241, 242}, + {244, 245, 246}, + {248, 249, 250} + }, + { + {227, 231, 239}, + {243, 247, 251}, + {236, 237, 238} + } + }, + { + { + {28, 29, 30}, + {60, 61, 62}, + {92, 93, 94} + }, + { + {156, 157, 158}, + {188, 189, 190}, + {220, 221, 222} + }, + { + {31, 63, 127}, + {159, 191, 255}, + {252, 253, 254} + } + } + } +}; + +/** + * @brief The number of bits, trits, and quints needed for a quant level. + */ +struct btq_count +{ + /** @brief The number of bits. */ + uint8_t bits:6; + + /** @brief The number of trits. */ + uint8_t trits:1; + + /** @brief The number of quints. */ + uint8_t quints:1; +}; + +/** + * @brief The table of bits, trits, and quints needed for a quant encode. + */ +static const std::array<btq_count, 21> btq_counts {{ + { 1, 0, 0 }, // QUANT_2 + { 0, 1, 0 }, // QUANT_3 + { 2, 0, 0 }, // QUANT_4 + { 0, 0, 1 }, // QUANT_5 + { 1, 1, 0 }, // QUANT_6 + { 3, 0, 0 }, // QUANT_8 + { 1, 0, 1 }, // QUANT_10 + { 2, 1, 0 }, // QUANT_12 + { 4, 0, 0 }, // QUANT_16 + { 2, 0, 1 }, // QUANT_20 + { 3, 1, 0 }, // QUANT_24 + { 5, 0, 0 }, // QUANT_32 + { 3, 0, 1 }, // QUANT_40 + { 4, 1, 0 }, // QUANT_48 + { 6, 0, 0 }, // QUANT_64 + { 4, 0, 1 }, // QUANT_80 + { 5, 1, 0 }, // QUANT_96 + { 7, 0, 0 }, // QUANT_128 + { 5, 0, 1 }, // QUANT_160 + { 6, 1, 0 }, // QUANT_192 + { 8, 0, 0 } // QUANT_256 +}}; + +/** + * @brief The sequence scale, round, and divisors needed to compute sizing. + * + * The length of a quantized sequence in bits is: + * (scale * <sequence_len> + round) / divisor + */ +struct ise_size +{ + /** @brief The scaling parameter. */ + uint8_t scale:6; + + /** @brief The divisor parameter. */ + uint8_t divisor:2; +}; + +/** + * @brief The table of scale, round, and divisors needed for quant sizing. + */ +static const std::array<ise_size, 21> ise_sizes {{ + { 1, 0 }, // QUANT_2 + { 8, 2 }, // QUANT_3 + { 2, 0 }, // QUANT_4 + { 7, 1 }, // QUANT_5 + { 13, 2 }, // QUANT_6 + { 3, 0 }, // QUANT_8 + { 10, 1 }, // QUANT_10 + { 18, 2 }, // QUANT_12 + { 4, 0 }, // QUANT_16 + { 13, 1 }, // QUANT_20 + { 23, 2 }, // QUANT_24 + { 5, 0 }, // QUANT_32 + { 16, 1 }, // QUANT_40 + { 28, 2 }, // QUANT_48 + { 6, 0 }, // QUANT_64 + { 19, 1 }, // QUANT_80 + { 33, 2 }, // QUANT_96 + { 7, 0 }, // QUANT_128 + { 22, 1 }, // QUANT_160 + { 38, 2 }, // QUANT_192 + { 8, 0 } // QUANT_256 +}}; + +/* See header for documentation. */ +unsigned int get_ise_sequence_bitcount( + unsigned int character_count, + quant_method quant_level +) { + // Cope with out-of bounds values - input might be invalid + if (static_cast<size_t>(quant_level) >= ise_sizes.size()) + { + // Arbitrary large number that's more than an ASTC block can hold + return 1024; + } + + auto& entry = ise_sizes[quant_level]; + unsigned int divisor = (entry.divisor << 1) + 1; + return (entry.scale * character_count + divisor - 1) / divisor; +} + +/** + * @brief Write up to 8 bits at an arbitrary bit offset. + * + * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may + * span two separate bytes in memory. + * + * @param value The value to write. + * @param bitcount The number of bits to write, starting from LSB. + * @param bitoffset The bit offset to store at, between 0 and 7. + * @param[in,out] ptr The data pointer to write to. + */ +static inline void write_bits( + unsigned int value, + unsigned int bitcount, + unsigned int bitoffset, + uint8_t ptr[2] +) { + unsigned int mask = (1 << bitcount) - 1; + value &= mask; + ptr += bitoffset >> 3; + bitoffset &= 7; + value <<= bitoffset; + mask <<= bitoffset; + mask = ~mask; + + ptr[0] &= mask; + ptr[0] |= value; + ptr[1] &= mask >> 8; + ptr[1] |= value >> 8; +} + +/** + * @brief Read up to 8 bits at an arbitrary bit offset. + * + * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may + * span two separate bytes in memory. + * + * @param bitcount The number of bits to read. + * @param bitoffset The bit offset to read from, between 0 and 7. + * @param[in,out] ptr The data pointer to read from. + * + * @return The read value. + */ +static inline unsigned int read_bits( + unsigned int bitcount, + unsigned int bitoffset, + const uint8_t* ptr +) { + unsigned int mask = (1 << bitcount) - 1; + ptr += bitoffset >> 3; + bitoffset &= 7; + unsigned int value = ptr[0] | (ptr[1] << 8); + value >>= bitoffset; + value &= mask; + return value; +} + +/* See header for documentation. */ +void encode_ise( + quant_method quant_level, + unsigned int character_count, + const uint8_t* input_data, + uint8_t* output_data, + unsigned int bit_offset +) { + promise(character_count > 0); + + unsigned int bits = btq_counts[quant_level].bits; + unsigned int trits = btq_counts[quant_level].trits; + unsigned int quints = btq_counts[quant_level].quints; + unsigned int mask = (1 << bits) - 1; + + // Write out trits and bits + if (trits) + { + unsigned int i = 0; + unsigned int full_trit_blocks = character_count / 5; + + for (unsigned int j = 0; j < full_trit_blocks; j++) + { + unsigned int i4 = input_data[i + 4] >> bits; + unsigned int i3 = input_data[i + 3] >> bits; + unsigned int i2 = input_data[i + 2] >> bits; + unsigned int i1 = input_data[i + 1] >> bits; + unsigned int i0 = input_data[i + 0] >> bits; + + uint8_t T = integer_of_trits[i4][i3][i2][i1][i0]; + + // The max size of a trit bit count is 6, so we can always safely + // pack a single MX value with the following 1 or 2 T bits. + uint8_t pack; + + // Element 0 + T0 + T1 + pack = (input_data[i++] & mask) | (((T >> 0) & 0x3) << bits); + write_bits(pack, bits + 2, bit_offset, output_data); + bit_offset += bits + 2; + + // Element 1 + T2 + T3 + pack = (input_data[i++] & mask) | (((T >> 2) & 0x3) << bits); + write_bits(pack, bits + 2, bit_offset, output_data); + bit_offset += bits + 2; + + // Element 2 + T4 + pack = (input_data[i++] & mask) | (((T >> 4) & 0x1) << bits); + write_bits(pack, bits + 1, bit_offset, output_data); + bit_offset += bits + 1; + + // Element 3 + T5 + T6 + pack = (input_data[i++] & mask) | (((T >> 5) & 0x3) << bits); + write_bits(pack, bits + 2, bit_offset, output_data); + bit_offset += bits + 2; + + // Element 4 + T7 + pack = (input_data[i++] & mask) | (((T >> 7) & 0x1) << bits); + write_bits(pack, bits + 1, bit_offset, output_data); + bit_offset += bits + 1; + } + + // Loop tail for a partial block + if (i != character_count) + { + // i4 cannot be present - we know the block is partial + // i0 must be present - we know the block isn't empty + unsigned int i4 = 0; + unsigned int i3 = i + 3 >= character_count ? 0 : input_data[i + 3] >> bits; + unsigned int i2 = i + 2 >= character_count ? 0 : input_data[i + 2] >> bits; + unsigned int i1 = i + 1 >= character_count ? 0 : input_data[i + 1] >> bits; + unsigned int i0 = input_data[i + 0] >> bits; + + uint8_t T = integer_of_trits[i4][i3][i2][i1][i0]; + + for (unsigned int j = 0; i < character_count; i++, j++) + { + // Truncated table as this iteration is always partital + static const uint8_t tbits[4] { 2, 2, 1, 2 }; + static const uint8_t tshift[4] { 0, 2, 4, 5 }; + + uint8_t pack = (input_data[i] & mask) | + (((T >> tshift[j]) & ((1 << tbits[j]) - 1)) << bits); + + write_bits(pack, bits + tbits[j], bit_offset, output_data); + bit_offset += bits + tbits[j]; + } + } + } + // Write out quints and bits + else if (quints) + { + unsigned int i = 0; + unsigned int full_quint_blocks = character_count / 3; + + for (unsigned int j = 0; j < full_quint_blocks; j++) + { + unsigned int i2 = input_data[i + 2] >> bits; + unsigned int i1 = input_data[i + 1] >> bits; + unsigned int i0 = input_data[i + 0] >> bits; + + uint8_t T = integer_of_quints[i2][i1][i0]; + + // The max size of a quint bit count is 5, so we can always safely + // pack a single M value with the following 2 or 3 T bits. + uint8_t pack; + + // Element 0 + pack = (input_data[i++] & mask) | (((T >> 0) & 0x7) << bits); + write_bits(pack, bits + 3, bit_offset, output_data); + bit_offset += bits + 3; + + // Element 1 + pack = (input_data[i++] & mask) | (((T >> 3) & 0x3) << bits); + write_bits(pack, bits + 2, bit_offset, output_data); + bit_offset += bits + 2; + + // Element 2 + pack = (input_data[i++] & mask) | (((T >> 5) & 0x3) << bits); + write_bits(pack, bits + 2, bit_offset, output_data); + bit_offset += bits + 2; + } + + // Loop tail for a partial block + if (i != character_count) + { + // i2 cannot be present - we know the block is partial + // i0 must be present - we know the block isn't empty + unsigned int i2 = 0; + unsigned int i1 = i + 1 >= character_count ? 0 : input_data[i + 1] >> bits; + unsigned int i0 = input_data[i + 0] >> bits; + + uint8_t T = integer_of_quints[i2][i1][i0]; + + for (unsigned int j = 0; i < character_count; i++, j++) + { + // Truncated table as this iteration is always partital + static const uint8_t tbits[2] { 3, 2 }; + static const uint8_t tshift[2] { 0, 3 }; + + uint8_t pack = (input_data[i] & mask) | + (((T >> tshift[j]) & ((1 << tbits[j]) - 1)) << bits); + + write_bits(pack, bits + tbits[j], bit_offset, output_data); + bit_offset += bits + tbits[j]; + } + } + } + // Write out just bits + else + { + for (unsigned int i = 0; i < character_count; i++) + { + write_bits(input_data[i], bits, bit_offset, output_data); + bit_offset += bits; + } + } +} + +/* See header for documentation. */ +void decode_ise( + quant_method quant_level, + unsigned int character_count, + const uint8_t* input_data, + uint8_t* output_data, + unsigned int bit_offset +) { + promise(character_count > 0); + + // Note: due to how the trit/quint-block unpacking is done in this function, we may write more + // temporary results than the number of outputs. The maximum actual number of results is 64 bit, + // but we keep 4 additional character_count of padding. + uint8_t results[68]; + uint8_t tq_blocks[22] { 0 }; // Trit-blocks or quint-blocks, must be zeroed + + unsigned int bits = btq_counts[quant_level].bits; + unsigned int trits = btq_counts[quant_level].trits; + unsigned int quints = btq_counts[quant_level].quints; + + unsigned int lcounter = 0; + unsigned int hcounter = 0; + + // Collect bits for each element, as well as bits for any trit-blocks and quint-blocks. + for (unsigned int i = 0; i < character_count; i++) + { + results[i] = static_cast<uint8_t>(read_bits(bits, bit_offset, input_data)); + bit_offset += bits; + + if (trits) + { + static const uint8_t bits_to_read[5] { 2, 2, 1, 2, 1 }; + static const uint8_t block_shift[5] { 0, 2, 4, 5, 7 }; + static const uint8_t next_lcounter[5] { 1, 2, 3, 4, 0 }; + static const uint8_t hcounter_incr[5] { 0, 0, 0, 0, 1 }; + unsigned int tdata = read_bits(bits_to_read[lcounter], bit_offset, input_data); + bit_offset += bits_to_read[lcounter]; + tq_blocks[hcounter] |= tdata << block_shift[lcounter]; + hcounter += hcounter_incr[lcounter]; + lcounter = next_lcounter[lcounter]; + } + + if (quints) + { + static const uint8_t bits_to_read[3] { 3, 2, 2 }; + static const uint8_t block_shift[3] { 0, 3, 5 }; + static const uint8_t next_lcounter[3] { 1, 2, 0 }; + static const uint8_t hcounter_incr[3] { 0, 0, 1 }; + unsigned int tdata = read_bits(bits_to_read[lcounter], bit_offset, input_data); + bit_offset += bits_to_read[lcounter]; + tq_blocks[hcounter] |= tdata << block_shift[lcounter]; + hcounter += hcounter_incr[lcounter]; + lcounter = next_lcounter[lcounter]; + } + } + + // Unpack trit-blocks or quint-blocks as needed + if (trits) + { + unsigned int trit_blocks = (character_count + 4) / 5; + promise(trit_blocks > 0); + for (unsigned int i = 0; i < trit_blocks; i++) + { + const uint8_t *tritptr = trits_of_integer[tq_blocks[i]]; + results[5 * i ] |= tritptr[0] << bits; + results[5 * i + 1] |= tritptr[1] << bits; + results[5 * i + 2] |= tritptr[2] << bits; + results[5 * i + 3] |= tritptr[3] << bits; + results[5 * i + 4] |= tritptr[4] << bits; + } + } + + if (quints) + { + unsigned int quint_blocks = (character_count + 2) / 3; + promise(quint_blocks > 0); + for (unsigned int i = 0; i < quint_blocks; i++) + { + const uint8_t *quintptr = quints_of_integer[tq_blocks[i]]; + results[3 * i ] |= quintptr[0] << bits; + results[3 * i + 1] |= quintptr[1] << bits; + results[3 * i + 2] |= quintptr[2] << bits; + } + } + + for (unsigned int i = 0; i < character_count; i++) + { + output_data[i] = results[i]; + } +} diff --git a/thirdparty/astcenc/astcenc_internal.h b/thirdparty/astcenc/astcenc_internal.h new file mode 100644 index 0000000000..0aa8fa0f81 --- /dev/null +++ b/thirdparty/astcenc/astcenc_internal.h @@ -0,0 +1,2196 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions and data declarations. + */ + +#ifndef ASTCENC_INTERNAL_INCLUDED +#define ASTCENC_INTERNAL_INCLUDED + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#if defined(ASTCENC_DIAGNOSTICS) + #include <cstdio> +#endif +#include <cstdlib> + +#include "astcenc.h" +#include "astcenc_mathlib.h" +#include "astcenc_vecmathlib.h" + +/** + * @brief Make a promise to the compiler's optimizer. + * + * A promise is an expression that the optimizer is can assume is true for to help it generate + * faster code. Common use cases for this are to promise that a for loop will iterate more than + * once, or that the loop iteration count is a multiple of a vector length, which avoids pre-loop + * checks and can avoid loop tails if loops are unrolled by the auto-vectorizer. + */ +#if defined(NDEBUG) + #if !defined(__clang__) && defined(_MSC_VER) + #define promise(cond) __assume(cond) + #elif defined(__clang__) + #if __has_builtin(__builtin_assume) + #define promise(cond) __builtin_assume(cond) + #elif __has_builtin(__builtin_unreachable) + #define promise(cond) if (!(cond)) { __builtin_unreachable(); } + #else + #define promise(cond) + #endif + #else // Assume GCC + #define promise(cond) if (!(cond)) { __builtin_unreachable(); } + #endif +#else + #define promise(cond) assert(cond) +#endif + +/* ============================================================================ + Constants +============================================================================ */ +#if !defined(ASTCENC_BLOCK_MAX_TEXELS) + #define ASTCENC_BLOCK_MAX_TEXELS 216 // A 3D 6x6x6 block +#endif + +/** @brief The maximum number of texels a block can support (6x6x6 block). */ +static constexpr unsigned int BLOCK_MAX_TEXELS { ASTCENC_BLOCK_MAX_TEXELS }; + +/** @brief The maximum number of components a block can support. */ +static constexpr unsigned int BLOCK_MAX_COMPONENTS { 4 }; + +/** @brief The maximum number of partitions a block can support. */ +static constexpr unsigned int BLOCK_MAX_PARTITIONS { 4 }; + +/** @brief The number of partitionings, per partition count, suported by the ASTC format. */ +static constexpr unsigned int BLOCK_MAX_PARTITIONINGS { 1024 }; + +/** @brief The maximum number of weights used during partition selection for texel clustering. */ +static constexpr uint8_t BLOCK_MAX_KMEANS_TEXELS { 64 }; + +/** @brief The maximum number of weights a block can support. */ +static constexpr unsigned int BLOCK_MAX_WEIGHTS { 64 }; + +/** @brief The maximum number of weights a block can support per plane in 2 plane mode. */ +static constexpr unsigned int BLOCK_MAX_WEIGHTS_2PLANE { BLOCK_MAX_WEIGHTS / 2 }; + +/** @brief The minimum number of weight bits a candidate encoding must encode. */ +static constexpr unsigned int BLOCK_MIN_WEIGHT_BITS { 24 }; + +/** @brief The maximum number of weight bits a candidate encoding can encode. */ +static constexpr unsigned int BLOCK_MAX_WEIGHT_BITS { 96 }; + +/** @brief The index indicating a bad (unused) block mode in the remap array. */ +static constexpr uint16_t BLOCK_BAD_BLOCK_MODE { 0xFFFFu }; + +/** @brief The index indicating a bad (unused) partitioning in the remap array. */ +static constexpr uint16_t BLOCK_BAD_PARTITIONING { 0xFFFFu }; + +/** @brief The number of partition index bits supported by the ASTC format . */ +static constexpr unsigned int PARTITION_INDEX_BITS { 10 }; + +/** @brief The offset of the plane 2 weights in shared weight arrays. */ +static constexpr unsigned int WEIGHTS_PLANE2_OFFSET { BLOCK_MAX_WEIGHTS_2PLANE }; + +/** @brief The sum of quantized weights for one texel. */ +static constexpr float WEIGHTS_TEXEL_SUM { 16.0f }; + +/** @brief The number of block modes supported by the ASTC format. */ +static constexpr unsigned int WEIGHTS_MAX_BLOCK_MODES { 2048 }; + +/** @brief The number of weight grid decimation modes supported by the ASTC format. */ +static constexpr unsigned int WEIGHTS_MAX_DECIMATION_MODES { 87 }; + +/** @brief The high default error used to initialize error trackers. */ +static constexpr float ERROR_CALC_DEFAULT { 1e30f }; + +/** + * @brief The minimum texel count for a block to use the one partition fast path. + * + * This setting skips 4x4 and 5x4 block sizes. + */ +static constexpr unsigned int TUNE_MIN_TEXELS_MODE0_FASTPATH { 24 }; + +/** + * @brief The maximum number of candidate encodings tested for each encoding mode. + * + * This can be dynamically reduced by the compression quality preset. + */ +static constexpr unsigned int TUNE_MAX_TRIAL_CANDIDATES { 8 }; + +/** + * @brief The maximum number of candidate partitionings tested for each encoding mode. + * + * This can be dynamically reduced by the compression quality preset. + */ +static constexpr unsigned int TUNE_MAX_PARTITIONING_CANDIDATES { 32 }; + +/** + * @brief The maximum quant level using full angular endpoint search method. + * + * The angular endpoint search is used to find the min/max weight that should + * be used for a given quantization level. It is effective but expensive, so + * we only use it where it has the most value - low quant levels with wide + * spacing. It is used below TUNE_MAX_ANGULAR_QUANT (inclusive). Above this we + * assume the min weight is 0.0f, and the max weight is 1.0f. + * + * Note the angular algorithm is vectorized, and using QUANT_12 exactly fills + * one 8-wide vector. Decreasing by one doesn't buy much performance, and + * increasing by one is disproportionately expensive. + */ +static constexpr unsigned int TUNE_MAX_ANGULAR_QUANT { 7 }; /* QUANT_12 */ + +static_assert((BLOCK_MAX_TEXELS % ASTCENC_SIMD_WIDTH) == 0, + "BLOCK_MAX_TEXELS must be multiple of ASTCENC_SIMD_WIDTH"); + +static_assert(BLOCK_MAX_TEXELS <= 216, + "BLOCK_MAX_TEXELS must not be greater than 216"); + +static_assert((BLOCK_MAX_WEIGHTS % ASTCENC_SIMD_WIDTH) == 0, + "BLOCK_MAX_WEIGHTS must be multiple of ASTCENC_SIMD_WIDTH"); + +static_assert((WEIGHTS_MAX_BLOCK_MODES % ASTCENC_SIMD_WIDTH) == 0, + "WEIGHTS_MAX_BLOCK_MODES must be multiple of ASTCENC_SIMD_WIDTH"); + + +/* ============================================================================ + Commonly used data structures +============================================================================ */ + +/** + * @brief The ASTC endpoint formats. + * + * Note, the values here are used directly in the encoding in the format so do not rearrange. + */ +enum endpoint_formats +{ + FMT_LUMINANCE = 0, + FMT_LUMINANCE_DELTA = 1, + FMT_HDR_LUMINANCE_LARGE_RANGE = 2, + FMT_HDR_LUMINANCE_SMALL_RANGE = 3, + FMT_LUMINANCE_ALPHA = 4, + FMT_LUMINANCE_ALPHA_DELTA = 5, + FMT_RGB_SCALE = 6, + FMT_HDR_RGB_SCALE = 7, + FMT_RGB = 8, + FMT_RGB_DELTA = 9, + FMT_RGB_SCALE_ALPHA = 10, + FMT_HDR_RGB = 11, + FMT_RGBA = 12, + FMT_RGBA_DELTA = 13, + FMT_HDR_RGB_LDR_ALPHA = 14, + FMT_HDR_RGBA = 15 +}; + +/** + * @brief The ASTC quantization methods. + * + * Note, the values here are used directly in the encoding in the format so do not rearrange. + */ +enum quant_method +{ + QUANT_2 = 0, + QUANT_3 = 1, + QUANT_4 = 2, + QUANT_5 = 3, + QUANT_6 = 4, + QUANT_8 = 5, + QUANT_10 = 6, + QUANT_12 = 7, + QUANT_16 = 8, + QUANT_20 = 9, + QUANT_24 = 10, + QUANT_32 = 11, + QUANT_40 = 12, + QUANT_48 = 13, + QUANT_64 = 14, + QUANT_80 = 15, + QUANT_96 = 16, + QUANT_128 = 17, + QUANT_160 = 18, + QUANT_192 = 19, + QUANT_256 = 20 +}; + +/** + * @brief The number of levels use by an ASTC quantization method. + * + * @param method The quantization method + * + * @return The number of levels used by @c method. + */ +static inline unsigned int get_quant_level(quant_method method) +{ + switch (method) + { + case QUANT_2: return 2; + case QUANT_3: return 3; + case QUANT_4: return 4; + case QUANT_5: return 5; + case QUANT_6: return 6; + case QUANT_8: return 8; + case QUANT_10: return 10; + case QUANT_12: return 12; + case QUANT_16: return 16; + case QUANT_20: return 20; + case QUANT_24: return 24; + case QUANT_32: return 32; + case QUANT_40: return 40; + case QUANT_48: return 48; + case QUANT_64: return 64; + case QUANT_80: return 80; + case QUANT_96: return 96; + case QUANT_128: return 128; + case QUANT_160: return 160; + case QUANT_192: return 192; + case QUANT_256: return 256; + } + + // Unreachable - the enum is fully described + return 0; +} + +/** + * @brief Computed metrics about a partition in a block. + */ +struct partition_metrics +{ + /** @brief The error-weighted average color in the partition. */ + vfloat4 avg; + + /** @brief The dominant error-weighted direction in the partition. */ + vfloat4 dir; +}; + +/** + * @brief Computed lines for a a three component analysis. + */ +struct partition_lines3 +{ + /** @brief Line for uncorrelated chroma. */ + line3 uncor_line; + + /** @brief Line for correlated chroma, passing though the origin. */ + line3 samec_line; + + /** @brief Post-processed line for uncorrelated chroma. */ + processed_line3 uncor_pline; + + /** @brief Post-processed line for correlated chroma, passing though the origin. */ + processed_line3 samec_pline; + + /** @brief The length of the line for uncorrelated chroma. */ + float uncor_line_len; + + /** @brief The length of the line for correlated chroma. */ + float samec_line_len; +}; + +/** + * @brief The partition information for a single partition. + * + * ASTC has a total of 1024 candidate partitions for each of 2/3/4 partition counts, although this + * 1024 includes seeds that generate duplicates of other seeds and seeds that generate completely + * empty partitions. These are both valid encodings, but astcenc will skip both during compression + * as they are not useful. + */ +struct partition_info +{ + /** @brief The number of partitions in this partitioning. */ + uint16_t partition_count; + + /** @brief The index (seed) of this partitioning. */ + uint16_t partition_index; + + /** + * @brief The number of texels in each partition. + * + * Note that some seeds result in zero texels assigned to a partition are valid, but are skipped + * by this compressor as there is no point spending bits encoding an unused color endpoint. + */ + uint8_t partition_texel_count[BLOCK_MAX_PARTITIONS]; + + /** @brief The partition of each texel in the block. */ + uint8_t partition_of_texel[BLOCK_MAX_TEXELS]; + + /** @brief The list of texels in each partition. */ + uint8_t texels_of_partition[BLOCK_MAX_PARTITIONS][BLOCK_MAX_TEXELS]; +}; + +/** + * @brief The weight grid information for a single decimation pattern. + * + * ASTC can store one weight per texel, but is also capable of storing lower resolution weight grids + * that are interpolated during decompression to assign a with to a texel. Storing fewer weights + * can free up a substantial amount of bits that we can then spend on more useful things, such as + * more accurate endpoints and weights, or additional partitions. + * + * This data structure is used to store information about a single weight grid decimation pattern, + * for a single block size. + */ +struct decimation_info +{ + /** @brief The total number of texels in the block. */ + uint8_t texel_count; + + /** @brief The maximum number of stored weights that contribute to each texel, between 1 and 4. */ + uint8_t max_texel_weight_count; + + /** @brief The total number of weights stored. */ + uint8_t weight_count; + + /** @brief The number of stored weights in the X dimension. */ + uint8_t weight_x; + + /** @brief The number of stored weights in the Y dimension. */ + uint8_t weight_y; + + /** @brief The number of stored weights in the Z dimension. */ + uint8_t weight_z; + + /** + * @brief The number of weights that contribute to each texel. + * Value is between 1 and 4. + */ + uint8_t texel_weight_count[BLOCK_MAX_TEXELS]; + + /** + * @brief The weight index of the N weights that are interpolated for each texel. + * Stored transposed to improve vectorization. + */ + uint8_t texel_weights_tr[4][BLOCK_MAX_TEXELS]; + + /** + * @brief The bilinear contribution of the N weights that are interpolated for each texel. + * Value is between 0 and 16, stored transposed to improve vectorization. + */ + uint8_t texel_weight_contribs_int_tr[4][BLOCK_MAX_TEXELS]; + + /** + * @brief The bilinear contribution of the N weights that are interpolated for each texel. + * Value is between 0 and 1, stored transposed to improve vectorization. + */ + alignas(ASTCENC_VECALIGN) float texel_weight_contribs_float_tr[4][BLOCK_MAX_TEXELS]; + + /** @brief The number of texels that each stored weight contributes to. */ + uint8_t weight_texel_count[BLOCK_MAX_WEIGHTS]; + + /** + * @brief The list of texels that use a specific weight index. + * Stored transposed to improve vectorization. + */ + uint8_t weight_texels_tr[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS]; + + /** + * @brief The bilinear contribution to the N texels that use each weight. + * Value is between 0 and 1, stored transposed to improve vectorization. + */ + alignas(ASTCENC_VECALIGN) float weights_texel_contribs_tr[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS]; + + /** + * @brief The bilinear contribution to the Nth texel that uses each weight. + * Value is between 0 and 1, stored transposed to improve vectorization. + */ + float texel_contrib_for_weight[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS]; +}; + +/** + * @brief Metadata for single block mode for a specific block size. + */ +struct block_mode +{ + /** @brief The block mode index in the ASTC encoded form. */ + uint16_t mode_index; + + /** @brief The decimation mode index in the compressor reindexed list. */ + uint8_t decimation_mode; + + /** @brief The weight quantization used by this block mode. */ + uint8_t quant_mode; + + /** @brief The weight quantization used by this block mode. */ + uint8_t weight_bits; + + /** @brief Is a dual weight plane used by this block mode? */ + uint8_t is_dual_plane : 1; + + /** + * @brief Get the weight quantization used by this block mode. + * + * @return The quantization level. + */ + inline quant_method get_weight_quant_mode() const + { + return static_cast<quant_method>(this->quant_mode); + } +}; + +/** + * @brief Metadata for single decimation mode for a specific block size. + */ +struct decimation_mode +{ + /** @brief The max weight precision for 1 plane, or -1 if not supported. */ + int8_t maxprec_1plane; + + /** @brief The max weight precision for 2 planes, or -1 if not supported. */ + int8_t maxprec_2planes; + + /** + * @brief Bitvector indicating weight quant modes used by active 1 plane block modes. + * + * Bit 0 = QUANT_2, Bit 1 = QUANT_3, etc. + */ + uint16_t refprec_1_plane; + + /** + * @brief Bitvector indicating weight quant methods used by active 2 plane block modes. + * + * Bit 0 = QUANT_2, Bit 1 = QUANT_3, etc. + */ + uint16_t refprec_2_planes; + + /** + * @brief Set a 1 plane weight quant as active. + * + * @param weight_quant The quant method to set. + */ + void set_ref_1_plane(quant_method weight_quant) + { + refprec_1_plane |= (1 << weight_quant); + } + + /** + * @brief Test if this mode is active below a given 1 plane weight quant (inclusive). + * + * @param max_weight_quant The max quant method to test. + */ + bool is_ref_1_plane(quant_method max_weight_quant) const + { + uint16_t mask = static_cast<uint16_t>((1 << (max_weight_quant + 1)) - 1); + return (refprec_1_plane & mask) != 0; + } + + /** + * @brief Set a 2 plane weight quant as active. + * + * @param weight_quant The quant method to set. + */ + void set_ref_2_plane(quant_method weight_quant) + { + refprec_2_planes |= static_cast<uint16_t>(1 << weight_quant); + } + + /** + * @brief Test if this mode is active below a given 2 plane weight quant (inclusive). + * + * @param max_weight_quant The max quant method to test. + */ + bool is_ref_2_plane(quant_method max_weight_quant) const + { + uint16_t mask = static_cast<uint16_t>((1 << (max_weight_quant + 1)) - 1); + return (refprec_2_planes & mask) != 0; + } +}; + +/** + * @brief Data tables for a single block size. + * + * The decimation tables store the information to apply weight grid dimension reductions. We only + * store the decimation modes that are actually needed by the current context; many of the possible + * modes will be unused (too many weights for the current block size or disabled by heuristics). The + * actual number of weights stored is @c decimation_mode_count, and the @c decimation_modes and + * @c decimation_tables arrays store the active modes contiguously at the start of the array. These + * entries are not stored in any particular order. + * + * The block mode tables store the unpacked block mode settings. Block modes are stored in the + * compressed block as an 11 bit field, but for any given block size and set of compressor + * heuristics, only a subset of the block modes will be used. The actual number of block modes + * stored is indicated in @c block_mode_count, and the @c block_modes array store the active modes + * contiguously at the start of the array. These entries are stored in incrementing "packed" value + * order, which doesn't mean much once unpacked. To allow decompressors to reference the packed data + * efficiently the @c block_mode_packed_index array stores the mapping between physical ID and the + * actual remapped array index. + */ +struct block_size_descriptor +{ + /** @brief The block X dimension, in texels. */ + uint8_t xdim; + + /** @brief The block Y dimension, in texels. */ + uint8_t ydim; + + /** @brief The block Z dimension, in texels. */ + uint8_t zdim; + + /** @brief The block total texel count. */ + uint8_t texel_count; + + /** + * @brief The number of stored decimation modes which are "always" modes. + * + * Always modes are stored at the start of the decimation_modes list. + */ + unsigned int decimation_mode_count_always; + + /** @brief The number of stored decimation modes for selected encodings. */ + unsigned int decimation_mode_count_selected; + + /** @brief The number of stored decimation modes for any encoding. */ + unsigned int decimation_mode_count_all; + + /** + * @brief The number of stored block modes which are "always" modes. + * + * Always modes are stored at the start of the block_modes list. + */ + unsigned int block_mode_count_1plane_always; + + /** @brief The number of stored block modes for active 1 plane encodings. */ + unsigned int block_mode_count_1plane_selected; + + /** @brief The number of stored block modes for active 1 and 2 plane encodings. */ + unsigned int block_mode_count_1plane_2plane_selected; + + /** @brief The number of stored block modes for any encoding. */ + unsigned int block_mode_count_all; + + /** @brief The number of selected partitionings for 1/2/3/4 partitionings. */ + unsigned int partitioning_count_selected[BLOCK_MAX_PARTITIONS]; + + /** @brief The number of partitionings for 1/2/3/4 partitionings. */ + unsigned int partitioning_count_all[BLOCK_MAX_PARTITIONS]; + + /** @brief The active decimation modes, stored in low indices. */ + decimation_mode decimation_modes[WEIGHTS_MAX_DECIMATION_MODES]; + + /** @brief The active decimation tables, stored in low indices. */ + alignas(ASTCENC_VECALIGN) decimation_info decimation_tables[WEIGHTS_MAX_DECIMATION_MODES]; + + /** @brief The packed block mode array index, or @c BLOCK_BAD_BLOCK_MODE if not active. */ + uint16_t block_mode_packed_index[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The active block modes, stored in low indices. */ + block_mode block_modes[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The active partition tables, stored in low indices per-count. */ + partition_info partitionings[(3 * BLOCK_MAX_PARTITIONINGS) + 1]; + + /** + * @brief The packed partition table array index, or @c BLOCK_BAD_PARTITIONING if not active. + * + * Indexed by partition_count - 2, containing 2, 3 and 4 partitions. + */ + uint16_t partitioning_packed_index[3][BLOCK_MAX_PARTITIONINGS]; + + /** @brief The active texels for k-means partition selection. */ + uint8_t kmeans_texels[BLOCK_MAX_KMEANS_TEXELS]; + + /** + * @brief The canonical 2-partition coverage pattern used during block partition search. + * + * Indexed by remapped index, not physical index. + */ + uint64_t coverage_bitmaps_2[BLOCK_MAX_PARTITIONINGS][2]; + + /** + * @brief The canonical 3-partition coverage pattern used during block partition search. + * + * Indexed by remapped index, not physical index. + */ + uint64_t coverage_bitmaps_3[BLOCK_MAX_PARTITIONINGS][3]; + + /** + * @brief The canonical 4-partition coverage pattern used during block partition search. + * + * Indexed by remapped index, not physical index. + */ + uint64_t coverage_bitmaps_4[BLOCK_MAX_PARTITIONINGS][4]; + + /** + * @brief Get the block mode structure for index @c block_mode. + * + * This function can only return block modes that are enabled by the current compressor config. + * Decompression from an arbitrary source should not use this without first checking that the + * packed block mode index is not @c BLOCK_BAD_BLOCK_MODE. + * + * @param block_mode The packed block mode index. + * + * @return The block mode structure. + */ + const block_mode& get_block_mode(unsigned int block_mode) const + { + unsigned int packed_index = this->block_mode_packed_index[block_mode]; + assert(packed_index != BLOCK_BAD_BLOCK_MODE && packed_index < this->block_mode_count_all); + return this->block_modes[packed_index]; + } + + /** + * @brief Get the decimation mode structure for index @c decimation_mode. + * + * This function can only return decimation modes that are enabled by the current compressor + * config. The mode array is stored packed, but this is only ever indexed by the packed index + * stored in the @c block_mode and never exists in an unpacked form. + * + * @param decimation_mode The packed decimation mode index. + * + * @return The decimation mode structure. + */ + const decimation_mode& get_decimation_mode(unsigned int decimation_mode) const + { + return this->decimation_modes[decimation_mode]; + } + + /** + * @brief Get the decimation info structure for index @c decimation_mode. + * + * This function can only return decimation modes that are enabled by the current compressor + * config. The mode array is stored packed, but this is only ever indexed by the packed index + * stored in the @c block_mode and never exists in an unpacked form. + * + * @param decimation_mode The packed decimation mode index. + * + * @return The decimation info structure. + */ + const decimation_info& get_decimation_info(unsigned int decimation_mode) const + { + return this->decimation_tables[decimation_mode]; + } + + /** + * @brief Get the partition info table for a given partition count. + * + * @param partition_count The number of partitions we want the table for. + * + * @return The pointer to the table of 1024 entries (for 2/3/4 parts) or 1 entry (for 1 part). + */ + const partition_info* get_partition_table(unsigned int partition_count) const + { + if (partition_count == 1) + { + partition_count = 5; + } + unsigned int index = (partition_count - 2) * BLOCK_MAX_PARTITIONINGS; + return this->partitionings + index; + } + + /** + * @brief Get the partition info structure for a given partition count and seed. + * + * @param partition_count The number of partitions we want the info for. + * @param index The partition seed (between 0 and 1023). + * + * @return The partition info structure. + */ + const partition_info& get_partition_info(unsigned int partition_count, unsigned int index) const + { + unsigned int packed_index = 0; + if (partition_count >= 2) + { + packed_index = this->partitioning_packed_index[partition_count - 2][index]; + } + + assert(packed_index != BLOCK_BAD_PARTITIONING && packed_index < this->partitioning_count_all[partition_count - 1]); + auto& result = get_partition_table(partition_count)[packed_index]; + assert(index == result.partition_index); + return result; + } + + /** + * @brief Get the partition info structure for a given partition count and seed. + * + * @param partition_count The number of partitions we want the info for. + * @param packed_index The raw array offset. + * + * @return The partition info structure. + */ + const partition_info& get_raw_partition_info(unsigned int partition_count, unsigned int packed_index) const + { + assert(packed_index != BLOCK_BAD_PARTITIONING && packed_index < this->partitioning_count_all[partition_count - 1]); + auto& result = get_partition_table(partition_count)[packed_index]; + return result; + } +}; + +/** + * @brief The image data for a single block. + * + * The @c data_[rgba] fields store the image data in an encoded SoA float form designed for easy + * vectorization. Input data is converted to float and stored as values between 0 and 65535. LDR + * data is stored as direct UNORM data, HDR data is stored as LNS data. + * + * The @c rgb_lns and @c alpha_lns fields that assigned a per-texel use of HDR are only used during + * decompression. The current compressor will always use HDR endpoint formats when in HDR mode. + */ +struct image_block +{ + /** @brief The input (compress) or output (decompress) data for the red color component. */ + alignas(ASTCENC_VECALIGN) float data_r[BLOCK_MAX_TEXELS]; + + /** @brief The input (compress) or output (decompress) data for the green color component. */ + alignas(ASTCENC_VECALIGN) float data_g[BLOCK_MAX_TEXELS]; + + /** @brief The input (compress) or output (decompress) data for the blue color component. */ + alignas(ASTCENC_VECALIGN) float data_b[BLOCK_MAX_TEXELS]; + + /** @brief The input (compress) or output (decompress) data for the alpha color component. */ + alignas(ASTCENC_VECALIGN) float data_a[BLOCK_MAX_TEXELS]; + + /** @brief The number of texels in the block. */ + uint8_t texel_count; + + /** @brief The original data for texel 0 for constant color block encoding. */ + vfloat4 origin_texel; + + /** @brief The min component value of all texels in the block. */ + vfloat4 data_min; + + /** @brief The mean component value of all texels in the block. */ + vfloat4 data_mean; + + /** @brief The max component value of all texels in the block. */ + vfloat4 data_max; + + /** @brief The relative error significance of the color channels. */ + vfloat4 channel_weight; + + /** @brief Is this grayscale block where R == G == B for all texels? */ + bool grayscale; + + /** @brief Set to 1 if a texel is using HDR RGB endpoints (decompression only). */ + uint8_t rgb_lns[BLOCK_MAX_TEXELS]; + + /** @brief Set to 1 if a texel is using HDR alpha endpoints (decompression only). */ + uint8_t alpha_lns[BLOCK_MAX_TEXELS]; + + /** @brief The X position of this block in the input or output image. */ + unsigned int xpos; + + /** @brief The Y position of this block in the input or output image. */ + unsigned int ypos; + + /** @brief The Z position of this block in the input or output image. */ + unsigned int zpos; + + /** + * @brief Get an RGBA texel value from the data. + * + * @param index The texel index. + * + * @return The texel in RGBA component ordering. + */ + inline vfloat4 texel(unsigned int index) const + { + return vfloat4(data_r[index], + data_g[index], + data_b[index], + data_a[index]); + } + + /** + * @brief Get an RGB texel value from the data. + * + * @param index The texel index. + * + * @return The texel in RGB0 component ordering. + */ + inline vfloat4 texel3(unsigned int index) const + { + return vfloat3(data_r[index], + data_g[index], + data_b[index]); + } + + /** + * @brief Get the default alpha value for endpoints that don't store it. + * + * The default depends on whether the alpha endpoint is LDR or HDR. + * + * @return The alpha value in the scaled range used by the compressor. + */ + inline float get_default_alpha() const + { + return this->alpha_lns[0] ? static_cast<float>(0x7800) : static_cast<float>(0xFFFF); + } + + /** + * @brief Test if a single color channel is constant across the block. + * + * Constant color channels are easier to compress as interpolating between two identical colors + * always returns the same value, irrespective of the weight used. They therefore can be ignored + * for the purposes of weight selection and use of a second weight plane. + * + * @return @c true if the channel is constant across the block, @c false otherwise. + */ + inline bool is_constant_channel(int channel) const + { + vmask4 lane_mask = vint4::lane_id() == vint4(channel); + vmask4 color_mask = this->data_min == this->data_max; + return any(lane_mask & color_mask); + } + + /** + * @brief Test if this block is a luminance block with constant 1.0 alpha. + * + * @return @c true if the block is a luminance block , @c false otherwise. + */ + inline bool is_luminance() const + { + float default_alpha = this->get_default_alpha(); + bool alpha1 = (this->data_min.lane<3>() == default_alpha) && + (this->data_max.lane<3>() == default_alpha); + return this->grayscale && alpha1; + } + + /** + * @brief Test if this block is a luminance block with variable alpha. + * + * @return @c true if the block is a luminance + alpha block , @c false otherwise. + */ + inline bool is_luminancealpha() const + { + float default_alpha = this->get_default_alpha(); + bool alpha1 = (this->data_min.lane<3>() == default_alpha) && + (this->data_max.lane<3>() == default_alpha); + return this->grayscale && !alpha1; + } +}; + +/** + * @brief Data structure storing the color endpoints for a block. + */ +struct endpoints +{ + /** @brief The number of partition endpoints stored. */ + unsigned int partition_count; + + /** @brief The colors for endpoint 0. */ + vfloat4 endpt0[BLOCK_MAX_PARTITIONS]; + + /** @brief The colors for endpoint 1. */ + vfloat4 endpt1[BLOCK_MAX_PARTITIONS]; +}; + +/** + * @brief Data structure storing the color endpoints and weights. + */ +struct endpoints_and_weights +{ + /** @brief True if all active values in weight_error_scale are the same. */ + bool is_constant_weight_error_scale; + + /** @brief The color endpoints. */ + endpoints ep; + + /** @brief The ideal weight for each texel; may be undecimated or decimated. */ + alignas(ASTCENC_VECALIGN) float weights[BLOCK_MAX_TEXELS]; + + /** @brief The ideal weight error scaling for each texel; may be undecimated or decimated. */ + alignas(ASTCENC_VECALIGN) float weight_error_scale[BLOCK_MAX_TEXELS]; +}; + +/** + * @brief Utility storing estimated errors from choosing particular endpoint encodings. + */ +struct encoding_choice_errors +{ + /** @brief Error of using LDR RGB-scale instead of complete endpoints. */ + float rgb_scale_error; + + /** @brief Error of using HDR RGB-scale instead of complete endpoints. */ + float rgb_luma_error; + + /** @brief Error of using luminance instead of RGB. */ + float luminance_error; + + /** @brief Error of discarding alpha and using a constant 1.0 alpha. */ + float alpha_drop_error; + + /** @brief Can we use delta offset encoding? */ + bool can_offset_encode; + + /** @brief Can we use blue contraction encoding? */ + bool can_blue_contract; +}; + +/** + * @brief Preallocated working buffers, allocated per thread during context creation. + */ +struct alignas(ASTCENC_VECALIGN) compression_working_buffers +{ + /** @brief Ideal endpoints and weights for plane 1. */ + endpoints_and_weights ei1; + + /** @brief Ideal endpoints and weights for plane 2. */ + endpoints_and_weights ei2; + + /** + * @brief Decimated ideal weight values in the ~0-1 range. + * + * Note that values can be slightly below zero or higher than one due to + * endpoint extents being inside the ideal color representation. + * + * For two planes, second plane starts at @c WEIGHTS_PLANE2_OFFSET offsets. + */ + alignas(ASTCENC_VECALIGN) float dec_weights_ideal[WEIGHTS_MAX_DECIMATION_MODES * BLOCK_MAX_WEIGHTS]; + + /** + * @brief Decimated quantized weight values in the unquantized 0-64 range. + * + * For two planes, second plane starts at @c WEIGHTS_PLANE2_OFFSET offsets. + */ + uint8_t dec_weights_uquant[WEIGHTS_MAX_BLOCK_MODES * BLOCK_MAX_WEIGHTS]; + + /** @brief Error of the best encoding combination for each block mode. */ + alignas(ASTCENC_VECALIGN) float errors_of_best_combination[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The best color quant for each block mode. */ + uint8_t best_quant_levels[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The best color quant for each block mode if modes are the same and we have spare bits. */ + uint8_t best_quant_levels_mod[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The best endpoint format for each partition. */ + uint8_t best_ep_formats[WEIGHTS_MAX_BLOCK_MODES][BLOCK_MAX_PARTITIONS]; + + /** @brief The total bit storage needed for quantized weights for each block mode. */ + int8_t qwt_bitcounts[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The cumulative error for quantized weights for each block mode. */ + float qwt_errors[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The low weight value in plane 1 for each block mode. */ + float weight_low_value1[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The high weight value in plane 1 for each block mode. */ + float weight_high_value1[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The low weight value in plane 1 for each quant level and decimation mode. */ + float weight_low_values1[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1]; + + /** @brief The high weight value in plane 1 for each quant level and decimation mode. */ + float weight_high_values1[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1]; + + /** @brief The low weight value in plane 2 for each block mode. */ + float weight_low_value2[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The high weight value in plane 2 for each block mode. */ + float weight_high_value2[WEIGHTS_MAX_BLOCK_MODES]; + + /** @brief The low weight value in plane 2 for each quant level and decimation mode. */ + float weight_low_values2[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1]; + + /** @brief The high weight value in plane 2 for each quant level and decimation mode. */ + float weight_high_values2[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1]; +}; + +struct dt_init_working_buffers +{ + uint8_t weight_count_of_texel[BLOCK_MAX_TEXELS]; + uint8_t grid_weights_of_texel[BLOCK_MAX_TEXELS][4]; + uint8_t weights_of_texel[BLOCK_MAX_TEXELS][4]; + + uint8_t texel_count_of_weight[BLOCK_MAX_WEIGHTS]; + uint8_t texels_of_weight[BLOCK_MAX_WEIGHTS][BLOCK_MAX_TEXELS]; + uint8_t texel_weights_of_weight[BLOCK_MAX_WEIGHTS][BLOCK_MAX_TEXELS]; +}; + +/** + * @brief Weight quantization transfer table. + * + * ASTC can store texel weights at many quantization levels, so for performance we store essential + * information about each level as a precomputed data structure. Unquantized weights are integers + * or floats in the range [0, 64]. + * + * This structure provides a table, used to estimate the closest quantized weight for a given + * floating-point weight. For each quantized weight, the corresponding unquantized values. For each + * quantized weight, a previous-value and a next-value. +*/ +struct quant_and_transfer_table +{ + /** @brief The unscrambled unquantized value. */ + int8_t quant_to_unquant[32]; + + /** @brief The scrambling order: scrambled_quant = map[unscrambled_quant]. */ + int8_t scramble_map[32]; + + /** @brief The unscrambling order: unscrambled_unquant = map[scrambled_quant]. */ + int8_t unscramble_and_unquant_map[32]; + + /** + * @brief A table of previous-and-next weights, indexed by the current unquantized value. + * * bits 7:0 = previous-index, unquantized + * * bits 15:8 = next-index, unquantized + */ + uint16_t prev_next_values[65]; +}; + +/** @brief The precomputed quant and transfer table. */ +extern const quant_and_transfer_table quant_and_xfer_tables[12]; + +/** @brief The block is an error block, and will return error color or NaN. */ +static constexpr uint8_t SYM_BTYPE_ERROR { 0 }; + +/** @brief The block is a constant color block using FP16 colors. */ +static constexpr uint8_t SYM_BTYPE_CONST_F16 { 1 }; + +/** @brief The block is a constant color block using UNORM16 colors. */ +static constexpr uint8_t SYM_BTYPE_CONST_U16 { 2 }; + +/** @brief The block is a normal non-constant color block. */ +static constexpr uint8_t SYM_BTYPE_NONCONST { 3 }; + +/** + * @brief A symbolic representation of a compressed block. + * + * The symbolic representation stores the unpacked content of a single + * @c physical_compressed_block, in a form which is much easier to access for + * the rest of the compressor code. + */ +struct symbolic_compressed_block +{ + /** @brief The block type, one of the @c SYM_BTYPE_* constants. */ + uint8_t block_type; + + /** @brief The number of partitions; valid for @c NONCONST blocks. */ + uint8_t partition_count; + + /** @brief Non-zero if the color formats matched; valid for @c NONCONST blocks. */ + uint8_t color_formats_matched; + + /** @brief The plane 2 color component, or -1 if single plane; valid for @c NONCONST blocks. */ + int8_t plane2_component; + + /** @brief The block mode; valid for @c NONCONST blocks. */ + uint16_t block_mode; + + /** @brief The partition index; valid for @c NONCONST blocks if 2 or more partitions. */ + uint16_t partition_index; + + /** @brief The endpoint color formats for each partition; valid for @c NONCONST blocks. */ + uint8_t color_formats[BLOCK_MAX_PARTITIONS]; + + /** @brief The endpoint color quant mode; valid for @c NONCONST blocks. */ + quant_method quant_mode; + + /** @brief The error of the current encoding; valid for @c NONCONST blocks. */ + float errorval; + + // We can't have both of these at the same time + union { + /** @brief The constant color; valid for @c CONST blocks. */ + int constant_color[BLOCK_MAX_COMPONENTS]; + + /** @brief The quantized endpoint color pairs; valid for @c NONCONST blocks. */ + uint8_t color_values[BLOCK_MAX_PARTITIONS][8]; + }; + + /** @brief The quantized and decimated weights. + * + * Weights are stored in the 0-64 unpacked range allowing them to be used + * directly in encoding passes without per-use unpacking. Packing happens + * when converting to/from the physical bitstream encoding. + * + * If dual plane, the second plane starts at @c weights[WEIGHTS_PLANE2_OFFSET]. + */ + uint8_t weights[BLOCK_MAX_WEIGHTS]; + + /** + * @brief Get the weight quantization used by this block mode. + * + * @return The quantization level. + */ + inline quant_method get_color_quant_mode() const + { + return this->quant_mode; + } +}; + +/** + * @brief A physical representation of a compressed block. + * + * The physical representation stores the raw bytes of the format in memory. + */ +struct physical_compressed_block +{ + /** @brief The ASTC encoded data for a single block. */ + uint8_t data[16]; +}; + + +/** + * @brief Parameter structure for @c compute_pixel_region_variance(). + * + * This function takes a structure to avoid spilling arguments to the stack on every function + * invocation, as there are a lot of parameters. + */ +struct pixel_region_args +{ + /** @brief The image to analyze. */ + const astcenc_image* img; + + /** @brief The component swizzle pattern. */ + astcenc_swizzle swz; + + /** @brief Should the algorithm bother with Z axis processing? */ + bool have_z; + + /** @brief The kernel radius for alpha processing. */ + unsigned int alpha_kernel_radius; + + /** @brief The X dimension of the working data to process. */ + unsigned int size_x; + + /** @brief The Y dimension of the working data to process. */ + unsigned int size_y; + + /** @brief The Z dimension of the working data to process. */ + unsigned int size_z; + + /** @brief The X position of first src and dst data in the data set. */ + unsigned int offset_x; + + /** @brief The Y position of first src and dst data in the data set. */ + unsigned int offset_y; + + /** @brief The Z position of first src and dst data in the data set. */ + unsigned int offset_z; + + /** @brief The working memory buffer. */ + vfloat4 *work_memory; +}; + +/** + * @brief Parameter structure for @c compute_averages_proc(). + */ +struct avg_args +{ + /** @brief The arguments for the nested variance computation. */ + pixel_region_args arg; + + /** @brief The image X dimensions. */ + unsigned int img_size_x; + + /** @brief The image Y dimensions. */ + unsigned int img_size_y; + + /** @brief The image Z dimensions. */ + unsigned int img_size_z; + + /** @brief The maximum working block dimensions in X and Y dimensions. */ + unsigned int blk_size_xy; + + /** @brief The maximum working block dimensions in Z dimensions. */ + unsigned int blk_size_z; + + /** @brief The working block memory size. */ + unsigned int work_memory_size; +}; + +#if defined(ASTCENC_DIAGNOSTICS) +/* See astcenc_diagnostic_trace header for details. */ +class TraceLog; +#endif + +/** + * @brief The astcenc compression context. + */ +struct astcenc_contexti +{ + /** @brief The configuration this context was created with. */ + astcenc_config config; + + /** @brief The thread count supported by this context. */ + unsigned int thread_count; + + /** @brief The block size descriptor this context was created with. */ + block_size_descriptor* bsd; + + /* + * Fields below here are not needed in a decompress-only build, but some remain as they are + * small and it avoids littering the code with #ifdefs. The most significant contributors to + * large structure size are omitted. + */ + + /** @brief The input image alpha channel averages table, may be @c nullptr if not needed. */ + float* input_alpha_averages; + + /** @brief The scratch working buffers, one per thread (see @c thread_count). */ + compression_working_buffers* working_buffers; + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + /** @brief The pixel region and variance worker arguments. */ + avg_args avg_preprocess_args; +#endif + +#if defined(ASTCENC_DIAGNOSTICS) + /** + * @brief The diagnostic trace logger. + * + * Note that this is a singleton, so can only be used in single threaded mode. It only exists + * here so we have a reference to close the file at the end of the capture. + */ + TraceLog* trace_log; +#endif +}; + +/* ============================================================================ + Functionality for managing block sizes and partition tables. +============================================================================ */ + +/** + * @brief Populate the block size descriptor for the target block size. + * + * This will also initialize the partition table metadata, which is stored as part of the BSD + * structure. + * + * @param x_texels The number of texels in the block X dimension. + * @param y_texels The number of texels in the block Y dimension. + * @param z_texels The number of texels in the block Z dimension. + * @param can_omit_modes Can we discard modes and partitionings that astcenc won't use? + * @param partition_count_cutoff The partition count cutoff to use, if we can omit partitionings. + * @param mode_cutoff The block mode percentile cutoff [0-1]. + * @param[out] bsd The descriptor to initialize. + */ +void init_block_size_descriptor( + unsigned int x_texels, + unsigned int y_texels, + unsigned int z_texels, + bool can_omit_modes, + unsigned int partition_count_cutoff, + float mode_cutoff, + block_size_descriptor& bsd); + +/** + * @brief Populate the partition tables for the target block size. + * + * Note the @c bsd descriptor must be initialized by calling @c init_block_size_descriptor() before + * calling this function. + * + * @param[out] bsd The block size information structure to populate. + * @param can_omit_partitionings True if we can we drop partitionings that astcenc won't use. + * @param partition_count_cutoff The partition count cutoff to use, if we can omit partitionings. + */ +void init_partition_tables( + block_size_descriptor& bsd, + bool can_omit_partitionings, + unsigned int partition_count_cutoff); + +/** + * @brief Get the percentile table for 2D block modes. + * + * This is an empirically determined prioritization of which block modes to use in the search in + * terms of their centile (lower centiles = more useful). + * + * Returns a dynamically allocated array; caller must free with delete[]. + * + * @param xdim The block x size. + * @param ydim The block y size. + * + * @return The unpacked table. + */ +const float* get_2d_percentile_table( + unsigned int xdim, + unsigned int ydim); + +/** + * @brief Query if a 2D block size is legal. + * + * @return True if legal, false otherwise. + */ +bool is_legal_2d_block_size( + unsigned int xdim, + unsigned int ydim); + +/** + * @brief Query if a 3D block size is legal. + * + * @return True if legal, false otherwise. + */ +bool is_legal_3d_block_size( + unsigned int xdim, + unsigned int ydim, + unsigned int zdim); + +/* ============================================================================ + Functionality for managing BISE quantization and unquantization. +============================================================================ */ + +/** + * @brief The precomputed table for quantizing color values. + * + * Converts unquant value in 0-255 range into quant value in 0-255 range. + * No BISE scrambling is applied at this stage. + * + * Indexed by [quant_mode - 4][data_value]. + */ +extern const uint8_t color_unquant_to_uquant_tables[17][256]; + +/** + * @brief The precomputed table for packing quantized color values. + * + * Converts quant value in 0-255 range into packed quant value in 0-N range, + * with BISE scrambling applied. + * + * Indexed by [quant_mode - 4][data_value]. + */ +extern const uint8_t color_uquant_to_scrambled_pquant_tables[17][256]; + +/** + * @brief The precomputed table for unpacking color values. + * + * Converts quant value in 0-N range into unpacked value in 0-255 range, + * with BISE unscrambling applied. + * + * Indexed by [quant_mode - 4][data_value]. + */ +extern const uint8_t* color_scrambled_pquant_to_uquant_tables[17]; + +/** + * @brief The precomputed quant mode storage table. + * + * Indexing by [integer_count/2][bits] gives us the quantization level for a given integer count and + * number of compressed storage bits. Returns -1 for cases where the requested integer count cannot + * ever fit in the supplied storage size. + */ +extern const int8_t quant_mode_table[10][128]; + +/** + * @brief Encode a packed string using BISE. + * + * Note that BISE can return strings that are not a whole number of bytes in length, and ASTC can + * start storing strings in a block at arbitrary bit offsets in the encoded data. + * + * @param quant_level The BISE alphabet size. + * @param character_count The number of characters in the string. + * @param input_data The unpacked string, one byte per character. + * @param[in,out] output_data The output packed string. + * @param bit_offset The starting offset in the output storage. + */ +void encode_ise( + quant_method quant_level, + unsigned int character_count, + const uint8_t* input_data, + uint8_t* output_data, + unsigned int bit_offset); + +/** + * @brief Decode a packed string using BISE. + * + * Note that BISE input strings are not a whole number of bytes in length, and ASTC can start + * strings at arbitrary bit offsets in the encoded data. + * + * @param quant_level The BISE alphabet size. + * @param character_count The number of characters in the string. + * @param input_data The packed string. + * @param[in,out] output_data The output storage, one byte per character. + * @param bit_offset The starting offset in the output storage. + */ +void decode_ise( + quant_method quant_level, + unsigned int character_count, + const uint8_t* input_data, + uint8_t* output_data, + unsigned int bit_offset); + +/** + * @brief Return the number of bits needed to encode an ISE sequence. + * + * This implementation assumes that the @c quant level is untrusted, given it may come from random + * data being decompressed, so we return an arbitrary unencodable size if that is the case. + * + * @param character_count The number of items in the sequence. + * @param quant_level The desired quantization level. + * + * @return The number of bits needed to encode the BISE string. + */ +unsigned int get_ise_sequence_bitcount( + unsigned int character_count, + quant_method quant_level); + +/* ============================================================================ + Functionality for managing color partitioning. +============================================================================ */ + +/** + * @brief Compute averages and dominant directions for each partition in a 2 component texture. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to be compressed. + * @param component1 The first component included in the analysis. + * @param component2 The second component included in the analysis. + * @param[out] pm The output partition metrics. + * - Only pi.partition_count array entries actually get initialized. + * - Direction vectors @c pm.dir are not normalized. + */ +void compute_avgs_and_dirs_2_comp( + const partition_info& pi, + const image_block& blk, + unsigned int component1, + unsigned int component2, + partition_metrics pm[BLOCK_MAX_PARTITIONS]); + +/** + * @brief Compute averages and dominant directions for each partition in a 3 component texture. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to be compressed. + * @param omitted_component The component excluded from the analysis. + * @param[out] pm The output partition metrics. + * - Only pi.partition_count array entries actually get initialized. + * - Direction vectors @c pm.dir are not normalized. + */ +void compute_avgs_and_dirs_3_comp( + const partition_info& pi, + const image_block& blk, + unsigned int omitted_component, + partition_metrics pm[BLOCK_MAX_PARTITIONS]); + +/** + * @brief Compute averages and dominant directions for each partition in a 3 component texture. + * + * This is a specialization of @c compute_avgs_and_dirs_3_comp where the omitted component is + * always alpha, a common case during partition search. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to be compressed. + * @param[out] pm The output partition metrics. + * - Only pi.partition_count array entries actually get initialized. + * - Direction vectors @c pm.dir are not normalized. + */ +void compute_avgs_and_dirs_3_comp_rgb( + const partition_info& pi, + const image_block& blk, + partition_metrics pm[BLOCK_MAX_PARTITIONS]); + +/** + * @brief Compute averages and dominant directions for each partition in a 4 component texture. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to be compressed. + * @param[out] pm The output partition metrics. + * - Only pi.partition_count array entries actually get initialized. + * - Direction vectors @c pm.dir are not normalized. + */ +void compute_avgs_and_dirs_4_comp( + const partition_info& pi, + const image_block& blk, + partition_metrics pm[BLOCK_MAX_PARTITIONS]); + +/** + * @brief Compute the RGB error for uncorrelated and same chroma projections. + * + * The output of compute averages and dirs is post processed to define two lines, both of which go + * through the mean-color-value. One line has a direction defined by the dominant direction; this + * is used to assess the error from using an uncorrelated color representation. The other line goes + * through (0,0,0) and is used to assess the error from using an RGBS color representation. + * + * This function computes the squared error when using these two representations. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to be compressed. + * @param[in,out] plines Processed line inputs, and line length outputs. + * @param[out] uncor_error The cumulative error for using the uncorrelated line. + * @param[out] samec_error The cumulative error for using the same chroma line. + */ +void compute_error_squared_rgb( + const partition_info& pi, + const image_block& blk, + partition_lines3 plines[BLOCK_MAX_PARTITIONS], + float& uncor_error, + float& samec_error); + +/** + * @brief Compute the RGBA error for uncorrelated and same chroma projections. + * + * The output of compute averages and dirs is post processed to define two lines, both of which go + * through the mean-color-value. One line has a direction defined by the dominant direction; this + * is used to assess the error from using an uncorrelated color representation. The other line goes + * through (0,0,0,1) and is used to assess the error from using an RGBS color representation. + * + * This function computes the squared error when using these two representations. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to be compressed. + * @param uncor_plines Processed uncorrelated partition lines for each partition. + * @param samec_plines Processed same chroma partition lines for each partition. + * @param[out] uncor_lengths The length of each components deviation from the line. + * @param[out] samec_lengths The length of each components deviation from the line. + * @param[out] uncor_error The cumulative error for using the uncorrelated line. + * @param[out] samec_error The cumulative error for using the same chroma line. + */ +void compute_error_squared_rgba( + const partition_info& pi, + const image_block& blk, + const processed_line4 uncor_plines[BLOCK_MAX_PARTITIONS], + const processed_line4 samec_plines[BLOCK_MAX_PARTITIONS], + float uncor_lengths[BLOCK_MAX_PARTITIONS], + float samec_lengths[BLOCK_MAX_PARTITIONS], + float& uncor_error, + float& samec_error); + +/** + * @brief Find the best set of partitions to trial for a given block. + * + * On return the @c best_partitions list will contain the two best partition + * candidates; one assuming data has uncorrelated chroma and one assuming the + * data has correlated chroma. The best candidate is returned first in the list. + * + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param partition_count The number of partitions in the block. + * @param partition_search_limit The number of candidate partition encodings to trial. + * @param[out] best_partitions The best partition candidates. + * @param requested_candidates The number of requested partitionings. May return fewer if + * candidates are not available. + * + * @return The actual number of candidates returned. + */ +unsigned int find_best_partition_candidates( + const block_size_descriptor& bsd, + const image_block& blk, + unsigned int partition_count, + unsigned int partition_search_limit, + unsigned int best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES], + unsigned int requested_candidates); + +/* ============================================================================ + Functionality for managing images and image related data. +============================================================================ */ + +/** + * @brief Setup computation of regional averages in an image. + * + * This must be done by only a single thread per image, before any thread calls + * @c compute_averages(). + * + * Results are written back into @c img->input_alpha_averages. + * + * @param img The input image data, also holds output data. + * @param alpha_kernel_radius The kernel radius (in pixels) for alpha mods. + * @param swz Input data component swizzle. + * @param[out] ag The average variance arguments to init. + * + * @return The number of tasks in the processing stage. + */ +unsigned int init_compute_averages( + const astcenc_image& img, + unsigned int alpha_kernel_radius, + const astcenc_swizzle& swz, + avg_args& ag); + +/** + * @brief Compute averages for a pixel region. + * + * The routine computes both in a single pass, using a summed-area table to decouple the running + * time from the averaging/variance kernel size. + * + * @param[out] ctx The compressor context storing the output data. + * @param arg The input parameter structure. + */ +void compute_pixel_region_variance( + astcenc_contexti& ctx, + const pixel_region_args& arg); +/** + * @brief Load a single image block from the input image. + * + * @param decode_mode The compression color profile. + * @param img The input image data. + * @param[out] blk The image block to populate. + * @param bsd The block size information. + * @param xpos The block X coordinate in the input image. + * @param ypos The block Y coordinate in the input image. + * @param zpos The block Z coordinate in the input image. + * @param swz The swizzle to apply on load. + */ +void load_image_block( + astcenc_profile decode_mode, + const astcenc_image& img, + image_block& blk, + const block_size_descriptor& bsd, + unsigned int xpos, + unsigned int ypos, + unsigned int zpos, + const astcenc_swizzle& swz); + +/** + * @brief Load a single image block from the input image. + * + * This specialized variant can be used only if the block is 2D LDR U8 data, + * with no swizzle. + * + * @param decode_mode The compression color profile. + * @param img The input image data. + * @param[out] blk The image block to populate. + * @param bsd The block size information. + * @param xpos The block X coordinate in the input image. + * @param ypos The block Y coordinate in the input image. + * @param zpos The block Z coordinate in the input image. + * @param swz The swizzle to apply on load. + */ +void load_image_block_fast_ldr( + astcenc_profile decode_mode, + const astcenc_image& img, + image_block& blk, + const block_size_descriptor& bsd, + unsigned int xpos, + unsigned int ypos, + unsigned int zpos, + const astcenc_swizzle& swz); + +/** + * @brief Store a single image block to the output image. + * + * @param[out] img The output image data. + * @param blk The image block to export. + * @param bsd The block size information. + * @param xpos The block X coordinate in the input image. + * @param ypos The block Y coordinate in the input image. + * @param zpos The block Z coordinate in the input image. + * @param swz The swizzle to apply on store. + */ +void store_image_block( + astcenc_image& img, + const image_block& blk, + const block_size_descriptor& bsd, + unsigned int xpos, + unsigned int ypos, + unsigned int zpos, + const astcenc_swizzle& swz); + +/* ============================================================================ + Functionality for computing endpoint colors and weights for a block. +============================================================================ */ + +/** + * @brief Compute ideal endpoint colors and weights for 1 plane of weights. + * + * The ideal endpoints define a color line for the partition. For each texel the ideal weight + * defines an exact position on the partition color line. We can then use these to assess the error + * introduced by removing and quantizing the weight grid. + * + * @param blk The image block color data to compress. + * @param pi The partition info for the current trial. + * @param[out] ei The endpoint and weight values. + */ +void compute_ideal_colors_and_weights_1plane( + const image_block& blk, + const partition_info& pi, + endpoints_and_weights& ei); + +/** + * @brief Compute ideal endpoint colors and weights for 2 planes of weights. + * + * The ideal endpoints define a color line for the partition. For each texel the ideal weight + * defines an exact position on the partition color line. We can then use these to assess the error + * introduced by removing and quantizing the weight grid. + * + * @param bsd The block size information. + * @param blk The image block color data to compress. + * @param plane2_component The component assigned to plane 2. + * @param[out] ei1 The endpoint and weight values for plane 1. + * @param[out] ei2 The endpoint and weight values for plane 2. + */ +void compute_ideal_colors_and_weights_2planes( + const block_size_descriptor& bsd, + const image_block& blk, + unsigned int plane2_component, + endpoints_and_weights& ei1, + endpoints_and_weights& ei2); + +/** + * @brief Compute the optimal unquantized weights for a decimation table. + * + * After computing ideal weights for the case for a complete weight grid, we we want to compute the + * ideal weights for the case where weights exist only for some texels. We do this with a + * steepest-descent grid solver which works as follows: + * + * First, for each actual weight, perform a weighted averaging of the texels affected by the weight. + * Then, set step size to <some initial value> and attempt one step towards the original ideal + * weight if it helps to reduce error. + * + * @param ei The non-decimated endpoints and weights. + * @param di The selected weight decimation. + * @param[out] dec_weight_ideal_value The ideal values for the decimated weight set. + */ +void compute_ideal_weights_for_decimation( + const endpoints_and_weights& ei, + const decimation_info& di, + float* dec_weight_ideal_value); + +/** + * @brief Compute the optimal quantized weights for a decimation table. + * + * We test the two closest weight indices in the allowed quantization range and keep the weight that + * is the closest match. + * + * @param di The selected weight decimation. + * @param low_bound The lowest weight allowed. + * @param high_bound The highest weight allowed. + * @param dec_weight_ideal_value The ideal weight set. + * @param[out] dec_weight_quant_uvalue The output quantized weight as a float. + * @param[out] dec_weight_uquant The output quantized weight as encoded int. + * @param quant_level The desired weight quant level. + */ +void compute_quantized_weights_for_decimation( + const decimation_info& di, + float low_bound, + float high_bound, + const float* dec_weight_ideal_value, + float* dec_weight_quant_uvalue, + uint8_t* dec_weight_uquant, + quant_method quant_level); + +/** + * @brief Compute the error of a decimated weight set for 1 plane. + * + * After computing ideal weights for the case with one weight per texel, we want to compute the + * error for decimated weight grids where weights are stored at a lower resolution. This function + * computes the error of the reduced grid, compared to the full grid. + * + * @param eai The ideal weights for the full grid. + * @param di The selected weight decimation. + * @param dec_weight_quant_uvalue The quantized weights for the decimated grid. + * + * @return The accumulated error. + */ +float compute_error_of_weight_set_1plane( + const endpoints_and_weights& eai, + const decimation_info& di, + const float* dec_weight_quant_uvalue); + +/** + * @brief Compute the error of a decimated weight set for 2 planes. + * + * After computing ideal weights for the case with one weight per texel, we want to compute the + * error for decimated weight grids where weights are stored at a lower resolution. This function + * computes the error of the reduced grid, compared to the full grid. + * + * @param eai1 The ideal weights for the full grid and plane 1. + * @param eai2 The ideal weights for the full grid and plane 2. + * @param di The selected weight decimation. + * @param dec_weight_quant_uvalue_plane1 The quantized weights for the decimated grid plane 1. + * @param dec_weight_quant_uvalue_plane2 The quantized weights for the decimated grid plane 2. + * + * @return The accumulated error. + */ +float compute_error_of_weight_set_2planes( + const endpoints_and_weights& eai1, + const endpoints_and_weights& eai2, + const decimation_info& di, + const float* dec_weight_quant_uvalue_plane1, + const float* dec_weight_quant_uvalue_plane2); + +/** + * @brief Pack a single pair of color endpoints as effectively as possible. + * + * The user requests a base color endpoint mode in @c format, but the quantizer may choose a + * delta-based representation. It will report back the format variant it actually used. + * + * @param color0 The input unquantized color0 endpoint for absolute endpoint pairs. + * @param color1 The input unquantized color1 endpoint for absolute endpoint pairs. + * @param rgbs_color The input unquantized RGBS variant endpoint for same chroma endpoints. + * @param rgbo_color The input unquantized RGBS variant endpoint for HDR endpoints. + * @param format The desired base format. + * @param[out] output The output storage for the quantized colors/ + * @param quant_level The quantization level requested. + * + * @return The actual endpoint mode used. + */ +uint8_t pack_color_endpoints( + vfloat4 color0, + vfloat4 color1, + vfloat4 rgbs_color, + vfloat4 rgbo_color, + int format, + uint8_t* output, + quant_method quant_level); + +/** + * @brief Unpack a single pair of encoded endpoints. + * + * Endpoints must be unscrambled and converted into the 0-255 range before calling this functions. + * + * @param decode_mode The decode mode (LDR, HDR). + * @param format The color endpoint mode used. + * @param input The raw array of encoded input integers. The length of this array + * depends on @c format; it can be safely assumed to be large enough. + * @param[out] rgb_hdr Is the endpoint using HDR for the RGB channels? + * @param[out] alpha_hdr Is the endpoint using HDR for the A channel? + * @param[out] output0 The output color for endpoint 0. + * @param[out] output1 The output color for endpoint 1. + */ +void unpack_color_endpoints( + astcenc_profile decode_mode, + int format, + const uint8_t* input, + bool& rgb_hdr, + bool& alpha_hdr, + vint4& output0, + vint4& output1); + +/** + * @brief Unpack a set of quantized and decimated weights. + * + * TODO: Can we skip this for non-decimated weights now that the @c scb is + * already storing unquantized weights? + * + * @param bsd The block size information. + * @param scb The symbolic compressed encoding. + * @param di The weight grid decimation table. + * @param is_dual_plane @c true if this is a dual plane block, @c false otherwise. + * @param[out] weights_plane1 The output array for storing the plane 1 weights. + * @param[out] weights_plane2 The output array for storing the plane 2 weights. + */ +void unpack_weights( + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const decimation_info& di, + bool is_dual_plane, + int weights_plane1[BLOCK_MAX_TEXELS], + int weights_plane2[BLOCK_MAX_TEXELS]); + +/** + * @brief Identify, for each mode, which set of color endpoint produces the best result. + * + * Returns the best @c tune_candidate_limit best looking modes, along with the ideal color encoding + * combination for each. The modified quantization level can be used when all formats are the same, + * as this frees up two additional bits of storage. + * + * @param pi The partition info for the current trial. + * @param blk The image block color data to compress. + * @param ep The ideal endpoints. + * @param qwt_bitcounts Bit counts for different quantization methods. + * @param qwt_errors Errors for different quantization methods. + * @param tune_candidate_limit The max number of candidates to return, may be less. + * @param start_block_mode The first block mode to inspect. + * @param end_block_mode The last block mode to inspect. + * @param[out] partition_format_specifiers The best formats per partition. + * @param[out] block_mode The best packed block mode indexes. + * @param[out] quant_level The best color quant level. + * @param[out] quant_level_mod The best color quant level if endpoints are the same. + * @param[out] tmpbuf Preallocated scratch buffers for the compressor. + * + * @return The actual number of candidate matches returned. + */ +unsigned int compute_ideal_endpoint_formats( + const partition_info& pi, + const image_block& blk, + const endpoints& ep, + const int8_t* qwt_bitcounts, + const float* qwt_errors, + unsigned int tune_candidate_limit, + unsigned int start_block_mode, + unsigned int end_block_mode, + uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS], + int block_mode[TUNE_MAX_TRIAL_CANDIDATES], + quant_method quant_level[TUNE_MAX_TRIAL_CANDIDATES], + quant_method quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES], + compression_working_buffers& tmpbuf); + +/** + * @brief For a given 1 plane weight set recompute the endpoint colors. + * + * As we quantize and decimate weights the optimal endpoint colors may change slightly, so we must + * recompute the ideal colors for a specific weight set. + * + * @param blk The image block color data to compress. + * @param pi The partition info for the current trial. + * @param di The weight grid decimation table. + * @param dec_weights_uquant The quantized weight set. + * @param[in,out] ep The color endpoints (modifed in place). + * @param[out] rgbs_vectors The RGB+scale vectors for LDR blocks. + * @param[out] rgbo_vectors The RGB+offset vectors for HDR blocks. + */ +void recompute_ideal_colors_1plane( + const image_block& blk, + const partition_info& pi, + const decimation_info& di, + const uint8_t* dec_weights_uquant, + endpoints& ep, + vfloat4 rgbs_vectors[BLOCK_MAX_PARTITIONS], + vfloat4 rgbo_vectors[BLOCK_MAX_PARTITIONS]); + +/** + * @brief For a given 2 plane weight set recompute the endpoint colors. + * + * As we quantize and decimate weights the optimal endpoint colors may change slightly, so we must + * recompute the ideal colors for a specific weight set. + * + * @param blk The image block color data to compress. + * @param bsd The block_size descriptor. + * @param di The weight grid decimation table. + * @param dec_weights_uquant_plane1 The quantized weight set for plane 1. + * @param dec_weights_uquant_plane2 The quantized weight set for plane 2. + * @param[in,out] ep The color endpoints (modifed in place). + * @param[out] rgbs_vector The RGB+scale color for LDR blocks. + * @param[out] rgbo_vector The RGB+offset color for HDR blocks. + * @param plane2_component The component assigned to plane 2. + */ +void recompute_ideal_colors_2planes( + const image_block& blk, + const block_size_descriptor& bsd, + const decimation_info& di, + const uint8_t* dec_weights_uquant_plane1, + const uint8_t* dec_weights_uquant_plane2, + endpoints& ep, + vfloat4& rgbs_vector, + vfloat4& rgbo_vector, + int plane2_component); + +/** + * @brief Expand the angular tables needed for the alternative to PCA that we use. + */ +void prepare_angular_tables(); + +/** + * @brief Compute the angular endpoints for one plane for each block mode. + * + * @param only_always Only consider block modes that are always enabled. + * @param bsd The block size descriptor for the current trial. + * @param dec_weight_ideal_value The ideal decimated unquantized weight values. + * @param max_weight_quant The maximum block mode weight quantization allowed. + * @param[out] tmpbuf Preallocated scratch buffers for the compressor. + */ +void compute_angular_endpoints_1plane( + bool only_always, + const block_size_descriptor& bsd, + const float* dec_weight_ideal_value, + unsigned int max_weight_quant, + compression_working_buffers& tmpbuf); + +/** + * @brief Compute the angular endpoints for two planes for each block mode. + * + * @param bsd The block size descriptor for the current trial. + * @param dec_weight_ideal_value The ideal decimated unquantized weight values. + * @param max_weight_quant The maximum block mode weight quantization allowed. + * @param[out] tmpbuf Preallocated scratch buffers for the compressor. + */ +void compute_angular_endpoints_2planes( + const block_size_descriptor& bsd, + const float* dec_weight_ideal_value, + unsigned int max_weight_quant, + compression_working_buffers& tmpbuf); + +/* ============================================================================ + Functionality for high level compression and decompression access. +============================================================================ */ + +/** + * @brief Compress an image block into a physical block. + * + * @param ctx The compressor context and configuration. + * @param blk The image block color data to compress. + * @param[out] pcb The physical compressed block output. + * @param[out] tmpbuf Preallocated scratch buffers for the compressor. + */ +void compress_block( + const astcenc_contexti& ctx, + const image_block& blk, + physical_compressed_block& pcb, + compression_working_buffers& tmpbuf); + +/** + * @brief Decompress a symbolic block in to an image block. + * + * @param decode_mode The decode mode (LDR, HDR, etc). + * @param bsd The block size information. + * @param xpos The X coordinate of the block in the overall image. + * @param ypos The Y coordinate of the block in the overall image. + * @param zpos The Z coordinate of the block in the overall image. + * @param[out] blk The decompressed image block color data. + */ +void decompress_symbolic_block( + astcenc_profile decode_mode, + const block_size_descriptor& bsd, + int xpos, + int ypos, + int zpos, + const symbolic_compressed_block& scb, + image_block& blk); + +/** + * @brief Compute the error between a symbolic block and the original input data. + * + * This function is specialized for 2 plane and 1 partition search. + * + * In RGBM mode this will reject blocks that attempt to encode a zero M value. + * + * @param config The compressor config. + * @param bsd The block size information. + * @param scb The symbolic compressed encoding. + * @param blk The original image block color data. + * + * @return Returns the computed error, or a negative value if the encoding + * should be rejected for any reason. + */ +float compute_symbolic_block_difference_2plane( + const astcenc_config& config, + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const image_block& blk); + +/** + * @brief Compute the error between a symbolic block and the original input data. + * + * This function is specialized for 1 plane and N partition search. + * + * In RGBM mode this will reject blocks that attempt to encode a zero M value. + * + * @param config The compressor config. + * @param bsd The block size information. + * @param scb The symbolic compressed encoding. + * @param blk The original image block color data. + * + * @return Returns the computed error, or a negative value if the encoding + * should be rejected for any reason. + */ +float compute_symbolic_block_difference_1plane( + const astcenc_config& config, + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const image_block& blk); + +/** + * @brief Compute the error between a symbolic block and the original input data. + * + * This function is specialized for 1 plane and 1 partition search. + * + * In RGBM mode this will reject blocks that attempt to encode a zero M value. + * + * @param config The compressor config. + * @param bsd The block size information. + * @param scb The symbolic compressed encoding. + * @param blk The original image block color data. + * + * @return Returns the computed error, or a negative value if the encoding + * should be rejected for any reason. + */ +float compute_symbolic_block_difference_1plane_1partition( + const astcenc_config& config, + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + const image_block& blk); + +/** + * @brief Convert a symbolic representation into a binary physical encoding. + * + * It is assumed that the symbolic encoding is valid and encodable, or + * previously flagged as an error block if an error color it to be encoded. + * + * @param bsd The block size information. + * @param scb The symbolic representation. + * @param[out] pcb The binary encoded data. + */ +void symbolic_to_physical( + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + physical_compressed_block& pcb); + +/** + * @brief Convert a binary physical encoding into a symbolic representation. + * + * This function can cope with arbitrary input data; output blocks will be + * flagged as an error block if the encoding is invalid. + * + * @param bsd The block size information. + * @param pcb The binary encoded data. + * @param[out] scb The output symbolic representation. + */ +void physical_to_symbolic( + const block_size_descriptor& bsd, + const physical_compressed_block& pcb, + symbolic_compressed_block& scb); + +/* ============================================================================ +Platform-specific functions. +============================================================================ */ +/** + * @brief Run-time detection if the host CPU supports the POPCNT extension. + * + * @return @c true if supported, @c false if not. + */ +bool cpu_supports_popcnt(); + +/** + * @brief Run-time detection if the host CPU supports F16C extension. + * + * @return @c true if supported, @c false if not. + */ +bool cpu_supports_f16c(); + +/** + * @brief Run-time detection if the host CPU supports SSE 4.1 extension. + * + * @return @c true if supported, @c false if not. + */ +bool cpu_supports_sse41(); + +/** + * @brief Run-time detection if the host CPU supports AVX 2 extension. + * + * @return @c true if supported, @c false if not. + */ +bool cpu_supports_avx2(); + +/** + * @brief Allocate an aligned memory buffer. + * + * Allocated memory must be freed by aligned_free; + * + * @param size The desired buffer size. + * @param align The desired buffer alignment; must be 2^N. + * + * @return The memory buffer pointer or nullptr on allocation failure. + */ +template<typename T> +T* aligned_malloc(size_t size, size_t align) +{ + void* ptr; + int error = 0; + +#if defined(_WIN32) + ptr = _aligned_malloc(size, align); +#else + error = posix_memalign(&ptr, align, size); +#endif + + if (error || (!ptr)) + { + return nullptr; + } + + return static_cast<T*>(ptr); +} + +/** + * @brief Free an aligned memory buffer. + * + * @param ptr The buffer to free. + */ +template<typename T> +void aligned_free(T* ptr) +{ +#if defined(_WIN32) + _aligned_free(reinterpret_cast<void*>(ptr)); +#else + free(reinterpret_cast<void*>(ptr)); +#endif +} + +#endif diff --git a/thirdparty/astcenc/astcenc_internal_entry.h b/thirdparty/astcenc/astcenc_internal_entry.h new file mode 100644 index 0000000000..4e8794547a --- /dev/null +++ b/thirdparty/astcenc/astcenc_internal_entry.h @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions and data declarations for the outer context. + * + * The outer context includes thread-pool management, which is slower to + * compile due to increased use of C++ stdlib. The inner context used in the + * majority of the codec library does not include this. + */ + +#ifndef ASTCENC_INTERNAL_ENTRY_INCLUDED +#define ASTCENC_INTERNAL_ENTRY_INCLUDED + +#include <atomic> +#include <condition_variable> +#include <functional> +#include <mutex> + +#include "astcenc_internal.h" + +/* ============================================================================ + Parallel execution control +============================================================================ */ + +/** + * @brief A simple counter-based manager for parallel task execution. + * + * The task processing execution consists of: + * + * * A single-threaded init stage. + * * A multi-threaded processing stage. + * * A condition variable so threads can wait for processing completion. + * + * The init stage will be executed by the first thread to arrive in the critical section, there is + * no main thread in the thread pool. + * + * The processing stage uses dynamic dispatch to assign task tickets to threads on an on-demand + * basis. Threads may each therefore executed different numbers of tasks, depending on their + * processing complexity. The task queue and the task tickets are just counters; the caller must map + * these integers to an actual processing partition in a specific problem domain. + * + * The exit wait condition is needed to ensure processing has finished before a worker thread can + * progress to the next stage of the pipeline. Specifically a worker may exit the processing stage + * because there are no new tasks to assign to it while other worker threads are still processing. + * Calling @c wait() will ensure that all other worker have finished before the thread can proceed. + * + * The basic usage model: + * + * // --------- From single-threaded code --------- + * + * // Reset the tracker state + * manager->reset() + * + * // --------- From multi-threaded code --------- + * + * // Run the stage init; only first thread actually runs the lambda + * manager->init(<lambda>) + * + * do + * { + * // Request a task assignment + * uint task_count; + * uint base_index = manager->get_tasks(<granule>, task_count); + * + * // Process any tasks we were given (task_count <= granule size) + * if (task_count) + * { + * // Run the user task processing code for N tasks here + * ... + * + * // Flag these tasks as complete + * manager->complete_tasks(task_count); + * } + * } while (task_count); + * + * // Wait for all threads to complete tasks before progressing + * manager->wait() + * + * // Run the stage term; only first thread actually runs the lambda + * manager->term(<lambda>) + */ +class ParallelManager +{ +private: + /** @brief Lock used for critical section and condition synchronization. */ + std::mutex m_lock; + + /** @brief True if the stage init() step has been executed. */ + bool m_init_done; + + /** @brief True if the stage term() step has been executed. */ + bool m_term_done; + + /** @brief Condition variable for tracking stage processing completion. */ + std::condition_variable m_complete; + + /** @brief Number of tasks started, but not necessarily finished. */ + std::atomic<unsigned int> m_start_count; + + /** @brief Number of tasks finished. */ + unsigned int m_done_count; + + /** @brief Number of tasks that need to be processed. */ + unsigned int m_task_count; + +public: + /** @brief Create a new ParallelManager. */ + ParallelManager() + { + reset(); + } + + /** + * @brief Reset the tracker for a new processing batch. + * + * This must be called from single-threaded code before starting the multi-threaded processing + * operations. + */ + void reset() + { + m_init_done = false; + m_term_done = false; + m_start_count = 0; + m_done_count = 0; + m_task_count = 0; + } + + /** + * @brief Trigger the pipeline stage init step. + * + * This can be called from multi-threaded code. The first thread to hit this will process the + * initialization. Other threads will block and wait for it to complete. + * + * @param init_func Callable which executes the stage initialization. It must return the + * total number of tasks in the stage. + */ + void init(std::function<unsigned int(void)> init_func) + { + std::lock_guard<std::mutex> lck(m_lock); + if (!m_init_done) + { + m_task_count = init_func(); + m_init_done = true; + } + } + + /** + * @brief Trigger the pipeline stage init step. + * + * This can be called from multi-threaded code. The first thread to hit this will process the + * initialization. Other threads will block and wait for it to complete. + * + * @param task_count Total number of tasks needing processing. + */ + void init(unsigned int task_count) + { + std::lock_guard<std::mutex> lck(m_lock); + if (!m_init_done) + { + m_task_count = task_count; + m_init_done = true; + } + } + + /** + * @brief Request a task assignment. + * + * Assign up to @c granule tasks to the caller for processing. + * + * @param granule Maximum number of tasks that can be assigned. + * @param[out] count Actual number of tasks assigned, or zero if no tasks were assigned. + * + * @return Task index of the first assigned task; assigned tasks increment from this. + */ + unsigned int get_task_assignment(unsigned int granule, unsigned int& count) + { + unsigned int base = m_start_count.fetch_add(granule, std::memory_order_relaxed); + if (base >= m_task_count) + { + count = 0; + return 0; + } + + count = astc::min(m_task_count - base, granule); + return base; + } + + /** + * @brief Complete a task assignment. + * + * Mark @c count tasks as complete. This will notify all threads blocked on @c wait() if this + * completes the processing of the stage. + * + * @param count The number of completed tasks. + */ + void complete_task_assignment(unsigned int count) + { + // Note: m_done_count cannot use an atomic without the mutex; this has a race between the + // update here and the wait() for other threads + std::unique_lock<std::mutex> lck(m_lock); + this->m_done_count += count; + if (m_done_count == m_task_count) + { + lck.unlock(); + m_complete.notify_all(); + } + } + + /** + * @brief Wait for stage processing to complete. + */ + void wait() + { + std::unique_lock<std::mutex> lck(m_lock); + m_complete.wait(lck, [this]{ return m_done_count == m_task_count; }); + } + + /** + * @brief Trigger the pipeline stage term step. + * + * This can be called from multi-threaded code. The first thread to hit this will process the + * work pool termination. Caller must have called @c wait() prior to calling this function to + * ensure that processing is complete. + * + * @param term_func Callable which executes the stage termination. + */ + void term(std::function<void(void)> term_func) + { + std::lock_guard<std::mutex> lck(m_lock); + if (!m_term_done) + { + term_func(); + m_term_done = true; + } + } +}; + +/** + * @brief The astcenc compression context. + */ +struct astcenc_context +{ + /** @brief The context internal state. */ + astcenc_contexti context; + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + /** @brief The parallel manager for averages computation. */ + ParallelManager manage_avg; + + /** @brief The parallel manager for compression. */ + ParallelManager manage_compress; +#endif + + /** @brief The parallel manager for decompression. */ + ParallelManager manage_decompress; +}; + +#endif diff --git a/thirdparty/astcenc/astcenc_mathlib.cpp b/thirdparty/astcenc/astcenc_mathlib.cpp new file mode 100644 index 0000000000..f276ac7e3d --- /dev/null +++ b/thirdparty/astcenc/astcenc_mathlib.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#include "astcenc_mathlib.h" + +/** + * @brief 64-bit rotate left. + * + * @param val The value to rotate. + * @param count The rotation, in bits. + */ +static inline uint64_t rotl(uint64_t val, int count) +{ + return (val << count) | (val >> (64 - count)); +} + +/* See header for documentation. */ +void astc::rand_init(uint64_t state[2]) +{ + state[0] = 0xfaf9e171cea1ec6bULL; + state[1] = 0xf1b318cc06af5d71ULL; +} + +/* See header for documentation. */ +uint64_t astc::rand(uint64_t state[2]) +{ + uint64_t s0 = state[0]; + uint64_t s1 = state[1]; + uint64_t res = s0 + s1; + s1 ^= s0; + state[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); + state[1] = rotl(s1, 37); + return res; +} diff --git a/thirdparty/astcenc/astcenc_mathlib.h b/thirdparty/astcenc/astcenc_mathlib.h new file mode 100644 index 0000000000..0540c4fedd --- /dev/null +++ b/thirdparty/astcenc/astcenc_mathlib.h @@ -0,0 +1,476 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/* + * This module implements a variety of mathematical data types and library + * functions used by the codec. + */ + +#ifndef ASTC_MATHLIB_H_INCLUDED +#define ASTC_MATHLIB_H_INCLUDED + +#include <cassert> +#include <cstdint> +#include <cmath> + +#ifndef ASTCENC_POPCNT + #if defined(__POPCNT__) + #define ASTCENC_POPCNT 1 + #else + #define ASTCENC_POPCNT 0 + #endif +#endif + +#ifndef ASTCENC_F16C + #if defined(__F16C__) + #define ASTCENC_F16C 1 + #else + #define ASTCENC_F16C 0 + #endif +#endif + +#ifndef ASTCENC_SSE + #if defined(__SSE4_2__) + #define ASTCENC_SSE 42 + #elif defined(__SSE4_1__) + #define ASTCENC_SSE 41 + #elif defined(__SSE2__) + #define ASTCENC_SSE 20 + #else + #define ASTCENC_SSE 0 + #endif +#endif + +#ifndef ASTCENC_AVX + #if defined(__AVX2__) + #define ASTCENC_AVX 2 + #elif defined(__AVX__) + #define ASTCENC_AVX 1 + #else + #define ASTCENC_AVX 0 + #endif +#endif + +#ifndef ASTCENC_NEON + #if defined(__aarch64__) + #define ASTCENC_NEON 1 + #else + #define ASTCENC_NEON 0 + #endif +#endif + +#if ASTCENC_AVX + #define ASTCENC_VECALIGN 32 +#else + #define ASTCENC_VECALIGN 16 +#endif + +#if ASTCENC_SSE != 0 || ASTCENC_AVX != 0 || ASTCENC_POPCNT != 0 + #include <immintrin.h> +#endif + +/* ============================================================================ + Fast math library; note that many of the higher-order functions in this set + use approximations which are less accurate, but faster, than <cmath> standard + library equivalents. + + Note: Many of these are not necessarily faster than simple C versions when + used on a single scalar value, but are included for testing purposes as most + have an option based on SSE intrinsics and therefore provide an obvious route + to future vectorization. +============================================================================ */ + +// Union for manipulation of float bit patterns +typedef union +{ + uint32_t u; + int32_t s; + float f; +} if32; + +// These are namespaced to avoid colliding with C standard library functions. +namespace astc +{ + +static const float PI = 3.14159265358979323846f; +static const float PI_OVER_TWO = 1.57079632679489661923f; + +/** + * @brief SP float absolute value. + * + * @param v The value to make absolute. + * + * @return The absolute value. + */ +static inline float fabs(float v) +{ + return std::fabs(v); +} + +/** + * @brief Test if a float value is a nan. + * + * @param v The value test. + * + * @return Zero is not a NaN, non-zero otherwise. + */ +static inline bool isnan(float v) +{ + return v != v; +} + +/** + * @brief Return the minimum of two values. + * + * For floats, NaNs are turned into @c q. + * + * @param p The first value to compare. + * @param q The second value to compare. + * + * @return The smallest value. + */ +template<typename T> +static inline T min(T p, T q) +{ + return p < q ? p : q; +} + +/** + * @brief Return the minimum of three values. + * + * For floats, NaNs are turned into @c r. + * + * @param p The first value to compare. + * @param q The second value to compare. + * @param r The third value to compare. + * + * @return The smallest value. + */ +template<typename T> +static inline T min(T p, T q, T r) +{ + return min(min(p, q), r); +} + +/** + * @brief Return the minimum of four values. + * + * For floats, NaNs are turned into @c s. + * + * @param p The first value to compare. + * @param q The second value to compare. + * @param r The third value to compare. + * @param s The fourth value to compare. + * + * @return The smallest value. + */ +template<typename T> +static inline T min(T p, T q, T r, T s) +{ + return min(min(p, q), min(r, s)); +} + +/** + * @brief Return the maximum of two values. + * + * For floats, NaNs are turned into @c q. + * + * @param p The first value to compare. + * @param q The second value to compare. + * + * @return The largest value. + */ +template<typename T> +static inline T max(T p, T q) +{ + return p > q ? p : q; +} + +/** + * @brief Return the maximum of three values. + * + * For floats, NaNs are turned into @c r. + * + * @param p The first value to compare. + * @param q The second value to compare. + * @param r The third value to compare. + * + * @return The largest value. + */ +template<typename T> +static inline T max(T p, T q, T r) +{ + return max(max(p, q), r); +} + +/** + * @brief Return the maximum of four values. + * + * For floats, NaNs are turned into @c s. + * + * @param p The first value to compare. + * @param q The second value to compare. + * @param r The third value to compare. + * @param s The fourth value to compare. + * + * @return The largest value. + */ +template<typename T> +static inline T max(T p, T q, T r, T s) +{ + return max(max(p, q), max(r, s)); +} + +/** + * @brief Clamp a value value between @c mn and @c mx. + * + * For floats, NaNs are turned into @c mn. + * + * @param v The value to clamp. + * @param mn The min value (inclusive). + * @param mx The max value (inclusive). + * + * @return The clamped value. + */ +template<typename T> +inline T clamp(T v, T mn, T mx) +{ + // Do not reorder; correct NaN handling relies on the fact that comparison + // with NaN returns false and will fall-though to the "min" value. + if (v > mx) return mx; + if (v > mn) return v; + return mn; +} + +/** + * @brief Clamp a float value between 0.0f and 1.0f. + * + * NaNs are turned into 0.0f. + * + * @param v The value to clamp. + * + * @return The clamped value. + */ +static inline float clamp1f(float v) +{ + return astc::clamp(v, 0.0f, 1.0f); +} + +/** + * @brief Clamp a float value between 0.0f and 255.0f. + * + * NaNs are turned into 0.0f. + * + * @param v The value to clamp. + * + * @return The clamped value. + */ +static inline float clamp255f(float v) +{ + return astc::clamp(v, 0.0f, 255.0f); +} + +/** + * @brief SP float round-down. + * + * @param v The value to round. + * + * @return The rounded value. + */ +static inline float flt_rd(float v) +{ + return std::floor(v); +} + +/** + * @brief SP float round-to-nearest and convert to integer. + * + * @param v The value to round. + * + * @return The rounded value. + */ +static inline int flt2int_rtn(float v) +{ + + return static_cast<int>(v + 0.5f); +} + +/** + * @brief SP float round down and convert to integer. + * + * @param v The value to round. + * + * @return The rounded value. + */ +static inline int flt2int_rd(float v) +{ + return static_cast<int>(v); +} + +/** + * @brief SP float bit-interpreted as an integer. + * + * @param v The value to bitcast. + * + * @return The converted value. + */ +static inline int float_as_int(float v) +{ + union { int a; float b; } u; + u.b = v; + return u.a; +} + +/** + * @brief Integer bit-interpreted as an SP float. + * + * @param v The value to bitcast. + * + * @return The converted value. + */ +static inline float int_as_float(int v) +{ + union { int a; float b; } u; + u.a = v; + return u.b; +} + +/** + * @brief Fast approximation of 1.0 / sqrt(val). + * + * @param v The input value. + * + * @return The approximated result. + */ +static inline float rsqrt(float v) +{ + return 1.0f / std::sqrt(v); +} + +/** + * @brief Fast approximation of sqrt(val). + * + * @param v The input value. + * + * @return The approximated result. + */ +static inline float sqrt(float v) +{ + return std::sqrt(v); +} + +/** + * @brief Extract mantissa and exponent of a float value. + * + * @param v The input value. + * @param[out] expo The output exponent. + * + * @return The mantissa. + */ +static inline float frexp(float v, int* expo) +{ + if32 p; + p.f = v; + *expo = ((p.u >> 23) & 0xFF) - 126; + p.u = (p.u & 0x807fffff) | 0x3f000000; + return p.f; +} + +/** + * @brief Initialize the seed structure for a random number generator. + * + * Important note: For the purposes of ASTC we want sets of random numbers to + * use the codec, but we want the same seed value across instances and threads + * to ensure that image output is stable across compressor runs and across + * platforms. Every PRNG created by this call will therefore return the same + * sequence of values ... + * + * @param state The state structure to initialize. + */ +void rand_init(uint64_t state[2]); + +/** + * @brief Return the next random number from the generator. + * + * This RNG is an implementation of the "xoroshoro-128+ 1.0" PRNG, based on the + * public-domain implementation given by David Blackman & Sebastiano Vigna at + * http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c + * + * @param state The state structure to use/update. + */ +uint64_t rand(uint64_t state[2]); + +} + +/* ============================================================================ + Softfloat library with fp32 and fp16 conversion functionality. +============================================================================ */ +#if (ASTCENC_F16C == 0) && (ASTCENC_NEON == 0) + /* narrowing float->float conversions */ + uint16_t float_to_sf16(float val); + float sf16_to_float(uint16_t val); +#endif + +/********************************* + Vector library +*********************************/ +#include "astcenc_vecmathlib.h" + +/********************************* + Declaration of line types +*********************************/ +// parametric line, 2D: The line is given by line = a + b * t. + +struct line2 +{ + vfloat4 a; + vfloat4 b; +}; + +// parametric line, 3D +struct line3 +{ + vfloat4 a; + vfloat4 b; +}; + +struct line4 +{ + vfloat4 a; + vfloat4 b; +}; + + +struct processed_line2 +{ + vfloat4 amod; + vfloat4 bs; +}; + +struct processed_line3 +{ + vfloat4 amod; + vfloat4 bs; +}; + +struct processed_line4 +{ + vfloat4 amod; + vfloat4 bs; +}; + +#endif diff --git a/thirdparty/astcenc/astcenc_mathlib_softfloat.cpp b/thirdparty/astcenc/astcenc_mathlib_softfloat.cpp new file mode 100644 index 0000000000..42db764549 --- /dev/null +++ b/thirdparty/astcenc/astcenc_mathlib_softfloat.cpp @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Soft-float library for IEEE-754. + */ +#if (ASTCENC_F16C == 0) && (ASTCENC_NEON == 0) + +#include "astcenc_mathlib.h" + +/* sized soft-float types. These are mapped to the sized integer + types of C99, instead of C's floating-point types; this is because + the library needs to maintain exact, bit-level control on all + operations on these data types. */ +typedef uint16_t sf16; +typedef uint32_t sf32; + +/****************************************** + helper functions and their lookup tables + ******************************************/ +/* count leading zeros functions. Only used when the input is nonzero. */ + +#if defined(__GNUC__) && (defined(__i386) || defined(__amd64)) +#elif defined(__arm__) && defined(__ARMCC_VERSION) +#elif defined(__arm__) && defined(__GNUC__) +#else + /* table used for the slow default versions. */ + static const uint8_t clz_table[256] = + { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; +#endif + +/* + 32-bit count-leading-zeros function: use the Assembly instruction whenever possible. */ +static uint32_t clz32(uint32_t inp) +{ + #if defined(__GNUC__) && (defined(__i386) || defined(__amd64)) + uint32_t bsr; + __asm__("bsrl %1, %0": "=r"(bsr):"r"(inp | 1)); + return 31 - bsr; + #else + #if defined(__arm__) && defined(__ARMCC_VERSION) + return __clz(inp); /* armcc builtin */ + #else + #if defined(__arm__) && defined(__GNUC__) + uint32_t lz; + __asm__("clz %0, %1": "=r"(lz):"r"(inp)); + return lz; + #else + /* slow default version */ + uint32_t summa = 24; + if (inp >= UINT32_C(0x10000)) + { + inp >>= 16; + summa -= 16; + } + if (inp >= UINT32_C(0x100)) + { + inp >>= 8; + summa -= 8; + } + return summa + clz_table[inp]; + #endif + #endif + #endif +} + +/* the five rounding modes that IEEE-754r defines */ +typedef enum +{ + SF_UP = 0, /* round towards positive infinity */ + SF_DOWN = 1, /* round towards negative infinity */ + SF_TOZERO = 2, /* round towards zero */ + SF_NEARESTEVEN = 3, /* round toward nearest value; if mid-between, round to even value */ + SF_NEARESTAWAY = 4 /* round toward nearest value; if mid-between, round away from zero */ +} roundmode; + + +static uint32_t rtne_shift32(uint32_t inp, uint32_t shamt) +{ + uint32_t vl1 = UINT32_C(1) << shamt; + uint32_t inp2 = inp + (vl1 >> 1); /* added 0.5 ULP */ + uint32_t msk = (inp | UINT32_C(1)) & vl1; /* nonzero if odd. '| 1' forces it to 1 if the shamt is 0. */ + msk--; /* negative if even, nonnegative if odd. */ + inp2 -= (msk >> 31); /* subtract epsilon before shift if even. */ + inp2 >>= shamt; + return inp2; +} + +static uint32_t rtna_shift32(uint32_t inp, uint32_t shamt) +{ + uint32_t vl1 = (UINT32_C(1) << shamt) >> 1; + inp += vl1; + inp >>= shamt; + return inp; +} + +static uint32_t rtup_shift32(uint32_t inp, uint32_t shamt) +{ + uint32_t vl1 = UINT32_C(1) << shamt; + inp += vl1; + inp--; + inp >>= shamt; + return inp; +} + +/* convert from FP16 to FP32. */ +static sf32 sf16_to_sf32(sf16 inp) +{ + uint32_t inpx = inp; + + /* + This table contains, for every FP16 sign/exponent value combination, + the difference between the input FP16 value and the value obtained + by shifting the correct FP32 result right by 13 bits. + This table allows us to handle every case except denormals and NaN + with just 1 table lookup, 2 shifts and 1 add. + */ + + #define WITH_MSB(a) (UINT32_C(a) | (1u << 31)) + static const uint32_t tbl[64] = + { + WITH_MSB(0x00000), 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, + 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, + 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, + 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, WITH_MSB(0x38000), + WITH_MSB(0x38000), 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, + 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, + 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, + 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, WITH_MSB(0x70000) + }; + + uint32_t res = tbl[inpx >> 10]; + res += inpx; + + /* Normal cases: MSB of 'res' not set. */ + if ((res & WITH_MSB(0)) == 0) + { + return res << 13; + } + + /* Infinity and Zero: 10 LSB of 'res' not set. */ + if ((res & 0x3FF) == 0) + { + return res << 13; + } + + /* NaN: the exponent field of 'inp' is non-zero. */ + if ((inpx & 0x7C00) != 0) + { + /* All NaNs are quietened. */ + return (res << 13) | 0x400000; + } + + /* Denormal cases */ + uint32_t sign = (inpx & 0x8000) << 16; + uint32_t mskval = inpx & 0x7FFF; + uint32_t leadingzeroes = clz32(mskval); + mskval <<= leadingzeroes; + return (mskval >> 8) + ((0x85 - leadingzeroes) << 23) + sign; +} + +/* Conversion routine that converts from FP32 to FP16. It supports denormals and all rounding modes. If a NaN is given as input, it is quietened. */ +static sf16 sf32_to_sf16(sf32 inp, roundmode rmode) +{ + /* for each possible sign/exponent combination, store a case index. This gives a 512-byte table */ + static const uint8_t tab[512] { + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 50, + + 5, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 55, + }; + + /* many of the cases below use a case-dependent magic constant. So we look up a magic constant before actually performing the switch. This table allows us to group cases, thereby minimizing code + size. */ + static const uint32_t tabx[60] { + UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0x8000), UINT32_C(0x80000000), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), + UINT32_C(1), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0x8000), UINT32_C(0x8001), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), + UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), + UINT32_C(0xC8001FFF), UINT32_C(0xC8000000), UINT32_C(0xC8000000), UINT32_C(0xC8000FFF), UINT32_C(0xC8001000), + UINT32_C(0x58000000), UINT32_C(0x38001FFF), UINT32_C(0x58000000), UINT32_C(0x58000FFF), UINT32_C(0x58001000), + UINT32_C(0x7C00), UINT32_C(0x7BFF), UINT32_C(0x7BFF), UINT32_C(0x7C00), UINT32_C(0x7C00), + UINT32_C(0xFBFF), UINT32_C(0xFC00), UINT32_C(0xFBFF), UINT32_C(0xFC00), UINT32_C(0xFC00), + UINT32_C(0x90000000), UINT32_C(0x90000000), UINT32_C(0x90000000), UINT32_C(0x90000000), UINT32_C(0x90000000), + UINT32_C(0x20000000), UINT32_C(0x20000000), UINT32_C(0x20000000), UINT32_C(0x20000000), UINT32_C(0x20000000) + }; + + uint32_t p; + uint32_t idx = rmode + tab[inp >> 23]; + uint32_t vlx = tabx[idx]; + switch (idx) + { + /* + Positive number which may be Infinity or NaN. + We need to check whether it is NaN; if it is, quieten it by setting the top bit of the mantissa. + (If we don't do this quieting, then a NaN that is distinguished only by having + its low-order bits set, would be turned into an INF. */ + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + /* + the input value is 0x7F800000 or 0xFF800000 if it is INF. + By subtracting 1, we get 7F7FFFFF or FF7FFFFF, that is, bit 23 becomes zero. + For NaNs, however, this operation will keep bit 23 with the value 1. + We can then extract bit 23, and logical-OR bit 9 of the result with this + bit in order to quieten the NaN (a Quiet NaN is a NaN where the top bit + of the mantissa is set.) + */ + p = (inp - 1) & UINT32_C(0x800000); /* zero if INF, nonzero if NaN. */ + return static_cast<sf16>(((inp + vlx) >> 13) | (p >> 14)); + /* + positive, exponent = 0, round-mode == UP; need to check whether number actually is 0. + If it is, then return 0, else return 1 (the smallest representable nonzero number) + */ + case 0: + /* + -inp will set the MSB if the input number is nonzero. + Thus (-inp) >> 31 will turn into 0 if the input number is 0 and 1 otherwise. + */ + return static_cast<sf16>(static_cast<uint32_t>((-static_cast<int32_t>(inp))) >> 31); + + /* + negative, exponent = , round-mode == DOWN, need to check whether number is + actually 0. If it is, return 0x8000 ( float -0.0 ) + Else return the smallest negative number ( 0x8001 ) */ + case 6: + /* + in this case 'vlx' is 0x80000000. By subtracting the input value from it, + we obtain a value that is 0 if the input value is in fact zero and has + the MSB set if it isn't. We then right-shift the value by 31 places to + get a value that is 0 if the input is -0.0 and 1 otherwise. + */ + return static_cast<sf16>(((vlx - inp) >> 31) + UINT32_C(0x8000)); + + /* + for all other cases involving underflow/overflow, we don't need to + do actual tests; we just return 'vlx'. + */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + return static_cast<sf16>(vlx); + + /* + for normal numbers, 'vlx' is the difference between the FP32 value of a number and the + FP16 representation of the same number left-shifted by 13 places. In addition, a rounding constant is + baked into 'vlx': for rounding-away-from zero, the constant is 2^13 - 1, causing roundoff away + from zero. for round-to-nearest away, the constant is 2^12, causing roundoff away from zero. + for round-to-nearest-even, the constant is 2^12 - 1. This causes correct round-to-nearest-even + except for odd input numbers. For odd input numbers, we need to add 1 to the constant. */ + + /* normal number, all rounding modes except round-to-nearest-even: */ + case 30: + case 31: + case 32: + case 34: + case 35: + case 36: + case 37: + case 39: + return static_cast<sf16>((inp + vlx) >> 13); + + /* normal number, round-to-nearest-even. */ + case 33: + case 38: + p = inp + vlx; + p += (inp >> 13) & 1; + return static_cast<sf16>(p >> 13); + + /* + the various denormal cases. These are not expected to be common, so their performance is a bit + less important. For each of these cases, we need to extract an exponent and a mantissa + (including the implicit '1'!), and then right-shift the mantissa by a shift-amount that + depends on the exponent. The shift must apply the correct rounding mode. 'vlx' is used to supply the + sign of the resulting denormal number. + */ + case 21: + case 22: + case 25: + case 27: + /* denormal, round towards zero. */ + p = 126 - ((inp >> 23) & 0xFF); + return static_cast<sf16>((((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000)) >> p) | vlx); + case 20: + case 26: + /* denormal, round away from zero. */ + p = 126 - ((inp >> 23) & 0xFF); + return static_cast<sf16>(rtup_shift32((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000), p) | vlx); + case 24: + case 29: + /* denormal, round to nearest-away */ + p = 126 - ((inp >> 23) & 0xFF); + return static_cast<sf16>(rtna_shift32((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000), p) | vlx); + case 23: + case 28: + /* denormal, round to nearest-even. */ + p = 126 - ((inp >> 23) & 0xFF); + return static_cast<sf16>(rtne_shift32((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000), p) | vlx); + } + + return 0; +} + +/* convert from soft-float to native-float */ +float sf16_to_float(uint16_t p) +{ + if32 i; + i.u = sf16_to_sf32(p); + return i.f; +} + +/* convert from native-float to soft-float */ +uint16_t float_to_sf16(float p) +{ + if32 i; + i.f = p; + return sf32_to_sf16(i.u, SF_NEARESTEVEN); +} + +#endif diff --git a/thirdparty/astcenc/astcenc_partition_tables.cpp b/thirdparty/astcenc/astcenc_partition_tables.cpp new file mode 100644 index 0000000000..cad42384d7 --- /dev/null +++ b/thirdparty/astcenc/astcenc_partition_tables.cpp @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for generating partition tables on demand. + */ + +#include "astcenc_internal.h" + +/** @brief The number of 64-bit words needed to represent a canonical partition bit pattern. */ +#define BIT_PATTERN_WORDS (((ASTCENC_BLOCK_MAX_TEXELS * 2) + 63) / 64) + +/** + * @brief Generate a canonical representation of a partition pattern. + * + * The returned value stores two bits per texel, for up to 6x6x6 texels, where the two bits store + * the remapped texel index. Remapping ensures that we only match on the partition pattern, + * independent of the partition order generated by the hash. + * + * @param texel_count The number of texels in the block. + * @param partition_of_texel The partition assignments, in hash order. + * @param[out] bit_pattern The output bit pattern representation. + */ +static void generate_canonical_partitioning( + unsigned int texel_count, + const uint8_t* partition_of_texel, + uint64_t bit_pattern[BIT_PATTERN_WORDS] +) { + // Clear the pattern + for (unsigned int i = 0; i < BIT_PATTERN_WORDS; i++) + { + bit_pattern[i] = 0; + } + + // Store a mapping to reorder the raw partitions so that the partitions are ordered such + // that the lowest texel index in partition N is smaller than the lowest texel index in + // partition N + 1. + int mapped_index[BLOCK_MAX_PARTITIONS]; + int map_weight_count = 0; + + for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONS; i++) + { + mapped_index[i] = -1; + } + + for (unsigned int i = 0; i < texel_count; i++) + { + int index = partition_of_texel[i]; + if (mapped_index[index] < 0) + { + mapped_index[index] = map_weight_count++; + } + + uint64_t xlat_index = mapped_index[index]; + bit_pattern[i >> 5] |= xlat_index << (2 * (i & 0x1F)); + } +} + +/** + * @brief Compare two canonical patterns to see if they are the same. + * + * @param part1 The first canonical bit pattern to check. + * @param part2 The second canonical bit pattern to check. + * + * @return @c true if the patterns are the same, @c false otherwise. + */ +static bool compare_canonical_partitionings( + const uint64_t part1[BIT_PATTERN_WORDS], + const uint64_t part2[BIT_PATTERN_WORDS] +) { + return (part1[0] == part2[0]) +#if BIT_PATTERN_WORDS > 1 + && (part1[1] == part2[1]) +#endif +#if BIT_PATTERN_WORDS > 2 + && (part1[2] == part2[2]) +#endif +#if BIT_PATTERN_WORDS > 3 + && (part1[3] == part2[3]) +#endif +#if BIT_PATTERN_WORDS > 4 + && (part1[4] == part2[4]) +#endif +#if BIT_PATTERN_WORDS > 5 + && (part1[5] == part2[5]) +#endif +#if BIT_PATTERN_WORDS > 6 + && (part1[6] == part2[6]) +#endif + ; +} + +/** + * @brief Hash function used for procedural partition assignment. + * + * @param inp The hash seed. + * + * @return The hashed value. + */ +static uint32_t hash52( + uint32_t inp +) { + inp ^= inp >> 15; + + // (2^4 + 1) * (2^7 + 1) * (2^17 - 1) + inp *= 0xEEDE0891; + inp ^= inp >> 5; + inp += inp << 16; + inp ^= inp >> 7; + inp ^= inp >> 3; + inp ^= inp << 6; + inp ^= inp >> 17; + return inp; +} + +/** + * @brief Select texel assignment for a single coordinate. + * + * @param seed The seed - the partition index from the block. + * @param x The texel X coordinate in the block. + * @param y The texel Y coordinate in the block. + * @param z The texel Z coordinate in the block. + * @param partition_count The total partition count of this encoding. + * @param small_block @c true if the block has fewer than 32 texels. + * + * @return The assigned partition index for this texel. + */ +static uint8_t select_partition( + int seed, + int x, + int y, + int z, + int partition_count, + bool small_block +) { + // For small blocks bias the coordinates to get better distribution + if (small_block) + { + x <<= 1; + y <<= 1; + z <<= 1; + } + + seed += (partition_count - 1) * 1024; + + uint32_t rnum = hash52(seed); + + uint8_t seed1 = rnum & 0xF; + uint8_t seed2 = (rnum >> 4) & 0xF; + uint8_t seed3 = (rnum >> 8) & 0xF; + uint8_t seed4 = (rnum >> 12) & 0xF; + uint8_t seed5 = (rnum >> 16) & 0xF; + uint8_t seed6 = (rnum >> 20) & 0xF; + uint8_t seed7 = (rnum >> 24) & 0xF; + uint8_t seed8 = (rnum >> 28) & 0xF; + uint8_t seed9 = (rnum >> 18) & 0xF; + uint8_t seed10 = (rnum >> 22) & 0xF; + uint8_t seed11 = (rnum >> 26) & 0xF; + uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF; + + // Squaring all the seeds in order to bias their distribution towards lower values. + seed1 *= seed1; + seed2 *= seed2; + seed3 *= seed3; + seed4 *= seed4; + seed5 *= seed5; + seed6 *= seed6; + seed7 *= seed7; + seed8 *= seed8; + seed9 *= seed9; + seed10 *= seed10; + seed11 *= seed11; + seed12 *= seed12; + + int sh1, sh2; + if (seed & 1) + { + sh1 = (seed & 2 ? 4 : 5); + sh2 = (partition_count == 3 ? 6 : 5); + } + else + { + sh1 = (partition_count == 3 ? 6 : 5); + sh2 = (seed & 2 ? 4 : 5); + } + + int sh3 = (seed & 0x10) ? sh1 : sh2; + + seed1 >>= sh1; + seed2 >>= sh2; + seed3 >>= sh1; + seed4 >>= sh2; + seed5 >>= sh1; + seed6 >>= sh2; + seed7 >>= sh1; + seed8 >>= sh2; + + seed9 >>= sh3; + seed10 >>= sh3; + seed11 >>= sh3; + seed12 >>= sh3; + + int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14); + int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10); + int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6); + int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2); + + // Apply the saw + a &= 0x3F; + b &= 0x3F; + c &= 0x3F; + d &= 0x3F; + + // Remove some of the components if we are to output < 4 partitions. + if (partition_count <= 3) + { + d = 0; + } + + if (partition_count <= 2) + { + c = 0; + } + + if (partition_count <= 1) + { + b = 0; + } + + uint8_t partition; + if (a >= b && a >= c && a >= d) + { + partition = 0; + } + else if (b >= c && b >= d) + { + partition = 1; + } + else if (c >= d) + { + partition = 2; + } + else + { + partition = 3; + } + + return partition; +} + +/** + * @brief Generate a single partition info structure. + * + * @param[out] bsd The block size information. + * @param partition_count The partition count of this partitioning. + * @param partition_index The partition index / seed of this partitioning. + * @param partition_remap_index The remapped partition index of this partitioning. + * @param[out] pi The partition info structure to populate. + * + * @return True if this is a useful partition index, False if we can skip it. + */ +static bool generate_one_partition_info_entry( + block_size_descriptor& bsd, + unsigned int partition_count, + unsigned int partition_index, + unsigned int partition_remap_index, + partition_info& pi +) { + int texels_per_block = bsd.texel_count; + bool small_block = texels_per_block < 32; + + uint8_t *partition_of_texel = pi.partition_of_texel; + + // Assign texels to partitions + int texel_idx = 0; + int counts[BLOCK_MAX_PARTITIONS] { 0 }; + for (unsigned int z = 0; z < bsd.zdim; z++) + { + for (unsigned int y = 0; y < bsd.ydim; y++) + { + for (unsigned int x = 0; x < bsd.xdim; x++) + { + uint8_t part = select_partition(partition_index, x, y, z, partition_count, small_block); + pi.texels_of_partition[part][counts[part]++] = static_cast<uint8_t>(texel_idx++); + *partition_of_texel++ = part; + } + } + } + + // Fill loop tail so we can overfetch later + for (unsigned int i = 0; i < partition_count; i++) + { + int ptex_count = counts[i]; + int ptex_count_simd = round_up_to_simd_multiple_vla(ptex_count); + for (int j = ptex_count; j < ptex_count_simd; j++) + { + pi.texels_of_partition[i][j] = pi.texels_of_partition[i][ptex_count - 1]; + } + } + + // Populate the actual procedural partition count + if (counts[0] == 0) + { + pi.partition_count = 0; + } + else if (counts[1] == 0) + { + pi.partition_count = 1; + } + else if (counts[2] == 0) + { + pi.partition_count = 2; + } + else if (counts[3] == 0) + { + pi.partition_count = 3; + } + else + { + pi.partition_count = 4; + } + + // Populate the partition index + pi.partition_index = static_cast<uint16_t>(partition_index); + + // Populate the coverage bitmaps for 2/3/4 partitions + uint64_t* bitmaps { nullptr }; + if (partition_count == 2) + { + bitmaps = bsd.coverage_bitmaps_2[partition_remap_index]; + } + else if (partition_count == 3) + { + bitmaps = bsd.coverage_bitmaps_3[partition_remap_index]; + } + else if (partition_count == 4) + { + bitmaps = bsd.coverage_bitmaps_4[partition_remap_index]; + } + + for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONS; i++) + { + pi.partition_texel_count[i] = static_cast<uint8_t>(counts[i]); + } + + // Valid partitionings have texels in all of the requested partitions + bool valid = pi.partition_count == partition_count; + + if (bitmaps) + { + // Populate the partition coverage bitmap + for (unsigned int i = 0; i < partition_count; i++) + { + bitmaps[i] = 0ULL; + } + + unsigned int texels_to_process = astc::min(bsd.texel_count, BLOCK_MAX_KMEANS_TEXELS); + for (unsigned int i = 0; i < texels_to_process; i++) + { + unsigned int idx = bsd.kmeans_texels[i]; + bitmaps[pi.partition_of_texel[idx]] |= 1ULL << i; + } + } + + return valid; +} + +static void build_partition_table_for_one_partition_count( + block_size_descriptor& bsd, + bool can_omit_partitionings, + unsigned int partition_count_cutoff, + unsigned int partition_count, + partition_info* ptab, + uint64_t* canonical_patterns +) { + unsigned int next_index = 0; + bsd.partitioning_count_selected[partition_count - 1] = 0; + bsd.partitioning_count_all[partition_count - 1] = 0; + + // Skip tables larger than config max partition count if we can omit modes + if (can_omit_partitionings && (partition_count > partition_count_cutoff)) + { + return; + } + + // Iterate through twice + // - Pass 0: Keep selected partitionings + // - Pass 1: Keep non-selected partitionings (skip if in omit mode) + unsigned int max_iter = can_omit_partitionings ? 1 : 2; + + // Tracker for things we built in the first iteration + uint8_t build[BLOCK_MAX_PARTITIONINGS] { 0 }; + for (unsigned int x = 0; x < max_iter; x++) + { + for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONINGS; i++) + { + // Don't include things we built in the first pass + if ((x == 1) && build[i]) + { + continue; + } + + bool keep_useful = generate_one_partition_info_entry(bsd, partition_count, i, next_index, ptab[next_index]); + if ((x == 0) && !keep_useful) + { + continue; + } + + generate_canonical_partitioning(bsd.texel_count, ptab[next_index].partition_of_texel, canonical_patterns + next_index * BIT_PATTERN_WORDS); + bool keep_canonical = true; + for (unsigned int j = 0; j < next_index; j++) + { + bool match = compare_canonical_partitionings(canonical_patterns + next_index * BIT_PATTERN_WORDS, canonical_patterns + j * BIT_PATTERN_WORDS); + if (match) + { + keep_canonical = false; + break; + } + } + + if (keep_useful && keep_canonical) + { + if (x == 0) + { + bsd.partitioning_packed_index[partition_count - 2][i] = static_cast<uint16_t>(next_index); + bsd.partitioning_count_selected[partition_count - 1]++; + bsd.partitioning_count_all[partition_count - 1]++; + build[i] = 1; + next_index++; + } + } + else + { + if (x == 1) + { + bsd.partitioning_packed_index[partition_count - 2][i] = static_cast<uint16_t>(next_index); + bsd.partitioning_count_all[partition_count - 1]++; + next_index++; + } + } + } + } +} + +/* See header for documentation. */ +void init_partition_tables( + block_size_descriptor& bsd, + bool can_omit_partitionings, + unsigned int partition_count_cutoff +) { + partition_info* par_tab2 = bsd.partitionings; + partition_info* par_tab3 = par_tab2 + BLOCK_MAX_PARTITIONINGS; + partition_info* par_tab4 = par_tab3 + BLOCK_MAX_PARTITIONINGS; + partition_info* par_tab1 = par_tab4 + BLOCK_MAX_PARTITIONINGS; + + generate_one_partition_info_entry(bsd, 1, 0, 0, *par_tab1); + bsd.partitioning_count_selected[0] = 1; + bsd.partitioning_count_all[0] = 1; + + uint64_t* canonical_patterns = new uint64_t[BLOCK_MAX_PARTITIONINGS * BIT_PATTERN_WORDS]; + + build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 2, par_tab2, canonical_patterns); + build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 3, par_tab3, canonical_patterns); + build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 4, par_tab4, canonical_patterns); + + delete[] canonical_patterns; +} diff --git a/thirdparty/astcenc/astcenc_percentile_tables.cpp b/thirdparty/astcenc/astcenc_percentile_tables.cpp new file mode 100644 index 0000000000..448ddcc968 --- /dev/null +++ b/thirdparty/astcenc/astcenc_percentile_tables.cpp @@ -0,0 +1,1251 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Percentile data tables for different block encodings. + * + * To reduce binary size the tables are stored using a packed differential encoding. + */ + +#include "astcenc_internal.h" + +#if !defined(ASTCENC_DECOMPRESS_ONLY) +/** + * @brief Structure containing packed percentile metadata. + * + * Note that percentile tables do not exist for 3D textures, so no zdim is stored. + */ +struct packed_percentile_table +{ + /** The block X dimension. */ + uint8_t xdim; + + /** The block Y dimension. */ + uint8_t ydim; + + /** The number of packed items in the 1 and 2 plane data. */ + uint16_t item_count[2]; + + /** The accumulator divisor for 1 and 2 plane data. */ + uint16_t difscales[2]; + + /** The initial accumulator values for 1 and 2 plane data. */ + uint16_t initial_percs[2]; + + /** The packed data for the 1 and 2 plane data. */ + const uint16_t *items[2]; +}; + +#if ASTCENC_BLOCK_MAX_TEXELS >= (4 * 4) +static const uint16_t percentile_arr_4x4_0[61] { + 0x0242, 0x7243, 0x6A51, 0x6A52, 0x5A41, 0x4A53, 0x8851, 0x3842, + 0x3852, 0x3853, 0x3043, 0xFA33, 0x1BDF, 0x2022, 0x1032, 0x29CE, + 0x21DE, 0x2823, 0x0813, 0x0A13, 0x0A31, 0x0A23, 0x09CF, 0x0833, + 0x0A32, 0x01DF, 0x0BDD, 0x0BCF, 0x0221, 0x095F, 0x0A01, 0x0BDE, + 0x0BCD, 0x0A22, 0x09AF, 0x0B5F, 0x0B4D, 0x0BCE, 0x0BBF, 0x0A11, + 0x01BF, 0x0202, 0x0B5D, 0x1203, 0x034E, 0x0B8E, 0x035E, 0x0212, + 0x032E, 0x0B4F, 0x03AF, 0x03AD, 0x03BD, 0x0BBE, 0x03AE, 0x039F, + 0x039E, 0x033E, 0x033F, 0x038F, 0x032F +}; + +static const uint16_t percentile_arr_4x4_1[84] { + 0x0452, 0xFFAE, 0x2433, 0x1DDF, 0x17CD, 0x1E21, 0x1C43, 0x1442, + 0x3FBE, 0x1FDD, 0x0E31, 0x0F4F, 0x1423, 0x0FBD, 0x1451, 0x0E03, + 0x05CF, 0x0C32, 0x0DDE, 0x27AD, 0x274E, 0x0E02, 0x0F5E, 0x07AF, + 0x0F5F, 0x0DCE, 0x0C41, 0x0422, 0x0613, 0x0E12, 0x0611, 0x0F3F, + 0x0601, 0x0DBF, 0x05DD, 0x075D, 0x0C02, 0x054E, 0x0431, 0x0413, + 0x079F, 0x05BE, 0x0F4D, 0x0403, 0x05AF, 0x055F, 0x05AE, 0x054F, + 0x0421, 0x05BD, 0x0DCD, 0x0411, 0x0412, 0x055E, 0x055D, 0x073D, + 0x058E, 0x072F, 0x072D, 0x079D, 0x0D2E, 0x0453, 0x078D, 0x053E, + 0x053F, 0x059E, 0x052F, 0x058F, 0x072E, 0x078F, 0x059F, 0x078E, + 0x071F, 0x073E, 0x051F, 0x070D, 0x079E, 0x070E, 0x071D, 0x0622, + 0x070F, 0x071E, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_4x4 { + 4, 4, + { 61, 84 }, + { 184, 141 }, + { 0, 53 }, + { percentile_arr_4x4_0, percentile_arr_4x4_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 4) +static const uint16_t percentile_arr_5x4_0[91] { + 0x02C1, 0xFAD1, 0xE8D3, 0xDAC2, 0xA8D2, 0x70D1, 0x50C2, 0x80C3, + 0xD2C3, 0x4AA2, 0x2AD2, 0x2242, 0x2251, 0x42A3, 0x1A43, 0x4A52, + 0x32B3, 0x2A41, 0x1042, 0x1851, 0x5892, 0x10A2, 0x2253, 0x10B2, + 0x10B3, 0x13DF, 0x3083, 0x08B1, 0x1043, 0x12B1, 0x0AB2, 0x1A93, + 0x1852, 0x1A33, 0x09CE, 0x08A3, 0x1022, 0x1283, 0x0853, 0x1AA1, + 0x1093, 0x11DE, 0x135F, 0x1832, 0x195F, 0x0A81, 0x11CF, 0x0A31, + 0x09DF, 0x0B4D, 0x09AF, 0x03CF, 0x0813, 0x03DD, 0x0A92, 0x0A82, + 0x03CD, 0x0023, 0x0BDE, 0x0BBF, 0x1232, 0x0221, 0x0291, 0x0A23, + 0x0833, 0x035D, 0x0BCE, 0x01BF, 0x0222, 0x134E, 0x0213, 0x0A01, + 0x0B4F, 0x0B5E, 0x038E, 0x032E, 0x03AF, 0x0A11, 0x03AD, 0x0203, + 0x0202, 0x0BBD, 0x033E, 0x03AE, 0x03BE, 0x0212, 0x033F, 0x039E, + 0x039F, 0x032F, 0x038F +}; + +static const uint16_t percentile_arr_5x4_1[104] { + 0x0433, 0xB621, 0x5452, 0x4443, 0x7FAE, 0xFCA3, 0x7CC2, 0x24B2, + 0x45DF, 0x44B3, 0x7631, 0x27CD, 0x1CD1, 0x1E03, 0x4FBE, 0x774F, + 0x1C42, 0x7691, 0x24A2, 0x2681, 0x3C23, 0x3C93, 0x0FBD, 0x1C32, + 0x1E82, 0x1E12, 0x0F4E, 0x1602, 0x0FAD, 0x0C51, 0x1FDD, 0x0E13, + 0x0DCF, 0x175E, 0x0C22, 0x175F, 0x15DE, 0x0CB1, 0x17AF, 0x1CC1, + 0x1F3F, 0x1483, 0x0441, 0x0C91, 0x04D2, 0x0DCE, 0x154E, 0x079F, + 0x0CA1, 0x0F5D, 0x0431, 0x15DD, 0x05BF, 0x0C92, 0x0611, 0x0C82, + 0x0402, 0x074D, 0x0DBD, 0x055E, 0x05BE, 0x0DCD, 0x0421, 0x05AF, + 0x0403, 0x0D4F, 0x055F, 0x05AE, 0x0413, 0x0E01, 0x055D, 0x073D, + 0x0C12, 0x0692, 0x0411, 0x072D, 0x078D, 0x079D, 0x058E, 0x0D2E, + 0x0453, 0x072F, 0x059E, 0x052F, 0x071F, 0x053F, 0x053E, 0x078F, + 0x058F, 0x051F, 0x0F2E, 0x059F, 0x078E, 0x073E, 0x071D, 0x070D, + 0x070E, 0x079E, 0x0622, 0x0683, 0x070F, 0x071E, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_5x4 { + 5, 4, + { 91, 104 }, + { 322, 464 }, + { 0, 202 }, + { percentile_arr_5x4_0, percentile_arr_5x4_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 5) +static const uint16_t percentile_arr_5x5_0[129] { + 0x00F3, 0xF8F2, 0x70E3, 0x62E1, 0x60E1, 0x4AC1, 0x3261, 0x38D3, + 0x3271, 0x5AF1, 0x5873, 0x2AD1, 0x28E2, 0x28F1, 0x2262, 0x9AC2, + 0x18D2, 0x1072, 0x1071, 0x22A2, 0x2062, 0x1A51, 0x10C2, 0x0892, + 0x08D1, 0x1AA3, 0x23EE, 0x08C3, 0x0BEF, 0x2242, 0x0863, 0x0AB3, + 0x0BFF, 0x0A93, 0x08A2, 0x0A41, 0x1083, 0x0842, 0x10B3, 0x21EE, + 0x10B2, 0x00B1, 0x1263, 0x12C3, 0x0A83, 0x0851, 0x11FE, 0x0253, + 0x09FD, 0x0A72, 0x09FF, 0x1AB2, 0x0BDF, 0x0A33, 0x0243, 0x0B7F, + 0x0AB1, 0x12D2, 0x0252, 0x096F, 0x00A3, 0x0893, 0x0822, 0x0843, + 0x097E, 0x097F, 0x01EF, 0x09CE, 0x03FE, 0x0A81, 0x036F, 0x0052, + 0x13FD, 0x0AA1, 0x1853, 0x036D, 0x0A92, 0x0832, 0x01DE, 0x0A82, + 0x0BED, 0x0231, 0x0BBF, 0x03DD, 0x0B6E, 0x01AF, 0x0813, 0x0023, + 0x0A91, 0x015F, 0x037E, 0x01CF, 0x0232, 0x0BCD, 0x0221, 0x0BDE, + 0x0213, 0x035F, 0x0B7D, 0x0223, 0x01BF, 0x0BCF, 0x01DF, 0x0033, + 0x0222, 0x03CE, 0x0A01, 0x03AF, 0x034D, 0x0B8E, 0x032E, 0x0203, + 0x0211, 0x0202, 0x0B5D, 0x03AD, 0x034E, 0x03AE, 0x034F, 0x033F, + 0x039F, 0x03BD, 0x03BE, 0x035E, 0x0212, 0x033E, 0x039E, 0x032F, + 0x038F +}; + +static const uint16_t percentile_arr_5x5_1[126] { + 0x0443, 0x6452, 0xFE21, 0x27AE, 0x2433, 0x1FCD, 0x25DF, 0x6CC2, + 0x2C62, 0x1F4F, 0x4C42, 0x1FBE, 0x0DEF, 0x34A3, 0x0E03, 0x54B2, + 0x1F7D, 0x17DD, 0x0DFF, 0x0CD1, 0x0E31, 0x0C71, 0x1CF1, 0x15FE, + 0x1691, 0x1681, 0x24B3, 0x174E, 0x0F6E, 0x0493, 0x175E, 0x1C51, + 0x17BD, 0x076D, 0x2CA2, 0x05EE, 0x1472, 0x2423, 0x0DCF, 0x0432, + 0x15DE, 0x0612, 0x0CD2, 0x0682, 0x0F5F, 0x07AD, 0x0602, 0x0CE1, + 0x0C91, 0x0FAF, 0x073F, 0x0E13, 0x0D7F, 0x0DCE, 0x0422, 0x0D7D, + 0x0441, 0x05FD, 0x0CB1, 0x0C83, 0x04C1, 0x0461, 0x0F9F, 0x0DDD, + 0x056E, 0x0C92, 0x0482, 0x0431, 0x05ED, 0x0D6F, 0x075D, 0x0402, + 0x057E, 0x0DBF, 0x04A1, 0x054E, 0x0F4D, 0x0403, 0x05CD, 0x0453, + 0x05AE, 0x0421, 0x0F1F, 0x05BE, 0x0601, 0x0611, 0x05BD, 0x05AF, + 0x078D, 0x072D, 0x073D, 0x055E, 0x0F9D, 0x0411, 0x0413, 0x0412, + 0x055F, 0x077E, 0x055D, 0x052E, 0x054F, 0x053E, 0x058E, 0x078F, + 0x059E, 0x071D, 0x0E92, 0x053F, 0x059F, 0x051F, 0x072F, 0x052F, + 0x070D, 0x079E, 0x058F, 0x072E, 0x070E, 0x078E, 0x070F, 0x073E, + 0x0622, 0x0683, 0x071E, 0x076F, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_5x5 { + 5, 5, + { 129, 126 }, + { 258, 291 }, + { 0, 116 }, + { percentile_arr_5x5_0, percentile_arr_5x5_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 5) +static const uint16_t percentile_arr_6x5_0[165] { + 0x0163, 0xF8F3, 0x9962, 0x8972, 0x7961, 0x7173, 0x6953, 0x5943, + 0x4B41, 0x3AE1, 0x38E3, 0x6971, 0x32C1, 0x28D3, 0x2A61, 0xC8F2, + 0x2271, 0x4873, 0x5B21, 0x3AD1, 0x1B13, 0x1952, 0x1B51, 0x12F1, + 0x1A62, 0x1322, 0x1951, 0x10E2, 0x1B31, 0x20F1, 0x2102, 0x2072, + 0x10D2, 0x1142, 0x2912, 0x3871, 0x2BEE, 0x0862, 0x1123, 0x0AC2, + 0x12A2, 0x0A51, 0x1922, 0x0941, 0x1BEF, 0x0B42, 0x08D1, 0x13FF, + 0x1933, 0x08C3, 0x08C2, 0x1131, 0x08E1, 0x2903, 0x0863, 0x0B32, + 0x1132, 0x1AC3, 0x0A42, 0x1A41, 0x0042, 0x21EE, 0x09FF, 0x03DF, + 0x0AA3, 0x11FE, 0x02B3, 0x0B11, 0x10B3, 0x0B03, 0x11FD, 0x0913, + 0x0A53, 0x037F, 0x1263, 0x0051, 0x0A33, 0x0B01, 0x016F, 0x0A72, + 0x1312, 0x08A2, 0x10B1, 0x0BFE, 0x11EF, 0x0B02, 0x0A52, 0x0043, + 0x0822, 0x01CE, 0x0A43, 0x097F, 0x036F, 0x08B2, 0x03FD, 0x0A83, + 0x0B33, 0x0AB1, 0x017E, 0x0B23, 0x0852, 0x02D2, 0x0BBF, 0x0BDD, + 0x03ED, 0x0AB2, 0x02A1, 0x0853, 0x036D, 0x0892, 0x0032, 0x0A31, + 0x0083, 0x09DE, 0x0A93, 0x08A3, 0x1213, 0x0BDE, 0x03CD, 0x036E, + 0x037E, 0x0A21, 0x0023, 0x0BCF, 0x01CF, 0x0013, 0x01AF, 0x0A92, + 0x0232, 0x035F, 0x0093, 0x0B7D, 0x015F, 0x0282, 0x01BF, 0x09DF, + 0x03CE, 0x0223, 0x0833, 0x0222, 0x03AF, 0x0A01, 0x0291, 0x0B4D, + 0x032E, 0x038E, 0x0203, 0x0281, 0x035D, 0x03AD, 0x0B9F, 0x0202, + 0x034F, 0x03BE, 0x0211, 0x03AE, 0x03BD, 0x0212, 0x034E, 0x033F, + 0x033E, 0x035E, 0x039E, 0x032F, 0x038F +}; + +static const uint16_t percentile_arr_6x5_1[145] { + 0x0443, 0xEFAE, 0x2CC2, 0x2E21, 0x2C52, 0x7C33, 0x47CD, 0x25DF, + 0x3CA3, 0xFFBE, 0x2551, 0x24B3, 0x474F, 0x1513, 0x2691, 0x1603, + 0x1462, 0x1D32, 0x14B2, 0x5442, 0x2CD2, 0x35EF, 0x0CD1, 0x3D22, + 0x17BD, 0x0FDD, 0x0DFF, 0x2631, 0x177D, 0x0CF1, 0x1E81, 0x0E82, + 0x1DFE, 0x0F5E, 0x0701, 0x2CA2, 0x1D03, 0x0F4E, 0x1471, 0x0C51, + 0x1F6E, 0x2FAF, 0x0561, 0x0C72, 0x176D, 0x0FAD, 0x0DEE, 0x05CF, + 0x0E13, 0x0F5F, 0x0E12, 0x0C23, 0x1E02, 0x1D12, 0x0CB1, 0x0C32, + 0x0C93, 0x15DE, 0x0F9F, 0x0F3F, 0x0D41, 0x0C41, 0x0CC1, 0x0D31, + 0x0C22, 0x05FD, 0x057F, 0x0D01, 0x0461, 0x04E1, 0x0D7D, 0x05CE, + 0x0502, 0x0C31, 0x05ED, 0x05DD, 0x0511, 0x0F11, 0x0491, 0x0D6F, + 0x0521, 0x056E, 0x0C83, 0x0D23, 0x04A1, 0x0C02, 0x075D, 0x05BF, + 0x0C21, 0x079D, 0x0482, 0x05BD, 0x0DBE, 0x05CD, 0x054E, 0x057E, + 0x0DAE, 0x074D, 0x078D, 0x0542, 0x0492, 0x05AF, 0x0611, 0x0F3D, + 0x0601, 0x071F, 0x055E, 0x059E, 0x0571, 0x054F, 0x0412, 0x0453, + 0x058E, 0x0413, 0x0D3E, 0x077E, 0x072D, 0x052E, 0x059F, 0x055D, + 0x072F, 0x0403, 0x0411, 0x058F, 0x055F, 0x0692, 0x078E, 0x053F, + 0x0D2F, 0x078F, 0x070D, 0x071D, 0x051F, 0x072E, 0x079E, 0x070E, + 0x070F, 0x073E, 0x0622, 0x0683, 0x0702, 0x071E, 0x076F, 0x07BF, + 0x07CE +}; + +static const packed_percentile_table block_pcd_6x5 { + 6, 5, + { 165, 145 }, + { 388, 405 }, + { 0, 156 }, + { percentile_arr_6x5_0, percentile_arr_6x5_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 6) +static const uint16_t percentile_arr_6x6_0[206] { + 0x006F, 0xF908, 0xF104, 0xE918, 0xE963, 0xD114, 0xB0F3, 0xA07E, + 0x7972, 0x705F, 0x687F, 0x6162, 0x5953, 0x586E, 0x610C, 0x524D, + 0x5973, 0x9943, 0x98E3, 0x904F, 0x8341, 0x7AC1, 0x3A61, 0x70D3, + 0xA073, 0x6AE1, 0x30F2, 0x3313, 0x2B21, 0x9A2E, 0x4322, 0x225D, + 0x2331, 0x2271, 0x22D1, 0x1A2D, 0x221F, 0x22F1, 0x1971, 0x6952, + 0x1951, 0x187D, 0x18F1, 0x1902, 0x185E, 0x1B51, 0x105D, 0x1A3D, + 0x30E2, 0x10D2, 0x1961, 0x12A2, 0x6072, 0x3942, 0x386D, 0x33EE, + 0x104E, 0x4923, 0x101E, 0x2122, 0x1251, 0x1141, 0x182F, 0x3133, + 0x080E, 0x1262, 0x123E, 0x1B32, 0x102E, 0x1931, 0x10D1, 0x1912, + 0x0871, 0x12C2, 0x08C2, 0x1103, 0x0B03, 0x1062, 0x083D, 0x08E1, + 0x1132, 0x184D, 0x0863, 0x08C3, 0x303F, 0x083E, 0x10B3, 0x12A3, + 0x0BEF, 0x0B11, 0x1A42, 0x2233, 0x13FF, 0x080F, 0x0A41, 0x0AC3, + 0x0842, 0x1A63, 0x0BDF, 0x09FF, 0x12B3, 0x124E, 0x0B12, 0x0B42, + 0x0A2F, 0x1253, 0x0913, 0x1051, 0x0B01, 0x120F, 0x0B02, 0x08A2, + 0x0BBF, 0x00B1, 0x22B1, 0x01EE, 0x1B33, 0x0B23, 0x0283, 0x13FD, + 0x0AB2, 0x11FD, 0x09FE, 0x0A43, 0x08B2, 0x0A1D, 0x0A52, 0x023F, + 0x101F, 0x01CE, 0x0A31, 0x0BDD, 0x0293, 0x1822, 0x12A1, 0x03FE, + 0x121E, 0x0843, 0x0272, 0x0B6F, 0x0052, 0x0A0D, 0x0BED, 0x12D2, + 0x1B7F, 0x1053, 0x0032, 0x01DE, 0x08A3, 0x020E, 0x0883, 0x09EF, + 0x0892, 0x0A21, 0x03CD, 0x0B5F, 0x0213, 0x0A32, 0x016F, 0x1292, + 0x03DE, 0x017E, 0x0BAF, 0x0223, 0x1093, 0x0BCF, 0x037E, 0x01DF, + 0x09CF, 0x015F, 0x09AF, 0x0023, 0x01BF, 0x0222, 0x0282, 0x03CE, + 0x1013, 0x036E, 0x097F, 0x0033, 0x0A01, 0x0B6D, 0x03BE, 0x037D, + 0x0281, 0x0BAE, 0x0203, 0x032E, 0x034D, 0x034F, 0x0291, 0x0211, + 0x038E, 0x03BD, 0x039E, 0x0BAD, 0x033E, 0x034E, 0x039F, 0x0202, + 0x035D, 0x0212, 0x033F, 0x035E, 0x038F, 0x032F +}; + +static const uint16_t percentile_arr_6x6_1[164] { + 0x07AE, 0x8443, 0x7E21, 0x77CD, 0x6C62, 0x9433, 0x6452, 0x34C2, + 0x5DDF, 0xC7BE, 0x25EF, 0x24A3, 0x3CF1, 0xFDFF, 0x177D, 0x1F4F, + 0xC551, 0x5CB3, 0x1532, 0x1513, 0x143E, 0x245D, 0x14B2, 0x2472, + 0x14D2, 0x1FBD, 0x1631, 0x2DFE, 0x1691, 0x17DD, 0x2E03, 0x376E, + 0x2442, 0x0F6D, 0x3C71, 0x2CD1, 0x2522, 0x6C51, 0x260D, 0x17AF, + 0x0DEE, 0x1C1F, 0x2F01, 0x142E, 0x0CA2, 0x0FAD, 0x3D03, 0x275E, + 0x1681, 0x274E, 0x1682, 0x1C23, 0x273F, 0x0F5F, 0x05DE, 0x15FD, + 0x0DCF, 0x1E02, 0x04B1, 0x144D, 0x0E12, 0x0D12, 0x1CC1, 0x0E13, + 0x1C6D, 0x0C32, 0x043D, 0x0C61, 0x0F9F, 0x04E1, 0x0DCE, 0x0D41, + 0x1C93, 0x0C22, 0x061D, 0x0D7F, 0x0C41, 0x0561, 0x0531, 0x0D21, + 0x0711, 0x0C91, 0x0501, 0x0C1E, 0x040F, 0x15DD, 0x0431, 0x0C2F, + 0x057D, 0x0C2D, 0x0DBE, 0x040E, 0x0D02, 0x0D11, 0x054E, 0x040D, + 0x0D23, 0x0DBF, 0x04A1, 0x05ED, 0x0C1D, 0x05BD, 0x072D, 0x056E, + 0x0483, 0x0F3D, 0x0482, 0x078D, 0x0F5D, 0x0453, 0x0D9E, 0x0C4E, + 0x05CD, 0x079D, 0x0402, 0x05AE, 0x0F1F, 0x0542, 0x074D, 0x056F, + 0x0421, 0x0D4F, 0x0601, 0x0571, 0x0492, 0x059F, 0x053F, 0x05AF, + 0x0611, 0x055E, 0x0D8E, 0x053E, 0x055D, 0x047D, 0x0411, 0x052E, + 0x058F, 0x051F, 0x055F, 0x0D7E, 0x072F, 0x052F, 0x0412, 0x078F, + 0x0403, 0x077E, 0x070D, 0x070E, 0x078E, 0x0F1D, 0x072E, 0x0413, + 0x070F, 0x0692, 0x079E, 0x060E, 0x0622, 0x0683, 0x0702, 0x071E, + 0x073E, 0x076F, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_6x6 { + 6, 6, + { 206, 164 }, + { 769, 644 }, + { 0, 256 }, + { percentile_arr_6x6_0, percentile_arr_6x6_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 5) +static const uint16_t percentile_arr_8x5_0[226] { + 0x0066, 0xF865, 0xE963, 0xA856, 0xA1F2, 0x9875, 0x91C3, 0x91E2, + 0x80F3, 0x8076, 0x61E3, 0x6153, 0x5172, 0x59D2, 0x51D3, 0x5047, + 0xA943, 0x49B3, 0x4846, 0x4962, 0xC037, 0x4173, 0x39F1, 0x7027, + 0xA2C1, 0x3AE1, 0x9341, 0x30D3, 0x5225, 0x2A61, 0x33C1, 0x28E3, + 0x53A1, 0x49C2, 0x2A06, 0x4055, 0x2006, 0x21D1, 0x2271, 0x4321, + 0x3873, 0x18F2, 0x2015, 0x1A15, 0x1857, 0x52D1, 0x3045, 0x4835, + 0x1952, 0x29E1, 0x3207, 0x1036, 0x1816, 0x2A16, 0x2971, 0x13B1, + 0x2A17, 0x2351, 0x1025, 0x1826, 0x30E2, 0x1262, 0x20F1, 0x1007, + 0x1072, 0x1151, 0x10D2, 0x1235, 0x1205, 0x1062, 0x4AF1, 0x1251, + 0x0B31, 0x1381, 0x13EE, 0x1B92, 0x13EF, 0x0942, 0x1AA2, 0x13FF, + 0x1161, 0x0B93, 0x19A2, 0x11B1, 0x08D1, 0x12C2, 0x0B13, 0x1B22, + 0x2123, 0x09A3, 0x2071, 0x1B7F, 0x1817, 0x0A42, 0x10C2, 0x1233, + 0x08C3, 0x0A41, 0x0B42, 0x09C1, 0x0933, 0x1AB3, 0x1382, 0x1BDF, + 0x2122, 0x0A53, 0x0AC3, 0x20E1, 0x0941, 0x0931, 0x0042, 0x0BA2, + 0x0AA3, 0x0992, 0x0863, 0x08B3, 0x11B2, 0x0902, 0x1283, 0x09FF, + 0x0B83, 0x0982, 0x0932, 0x0BFE, 0x0B32, 0x0BBF, 0x11FE, 0x036F, + 0x0851, 0x08B1, 0x18A2, 0x11EE, 0x0A52, 0x0BB2, 0x01FD, 0x0A43, + 0x1A63, 0x1193, 0x0B91, 0x0043, 0x1231, 0x0A26, 0x0AB1, 0x03FD, + 0x096F, 0x00B2, 0x0983, 0x0A72, 0x01CE, 0x0BDD, 0x0022, 0x0B11, + 0x1213, 0x0B6D, 0x017E, 0x1333, 0x0112, 0x0852, 0x02D2, 0x097F, + 0x01EF, 0x0AB2, 0x0293, 0x0853, 0x0BED, 0x0B12, 0x1303, 0x02A1, + 0x0892, 0x0032, 0x0883, 0x0B6E, 0x0292, 0x0A32, 0x037E, 0x0B23, + 0x0103, 0x0A21, 0x0B01, 0x0302, 0x0BCD, 0x00A3, 0x0BCF, 0x0BDE, + 0x0113, 0x01DE, 0x0B5F, 0x0013, 0x0BAF, 0x0223, 0x0222, 0x0A82, + 0x0833, 0x0023, 0x09CF, 0x037D, 0x01AF, 0x095F, 0x03CE, 0x09DF, + 0x01BF, 0x0893, 0x0203, 0x0201, 0x0B4D, 0x03BE, 0x032E, 0x03AE, + 0x0291, 0x0A02, 0x0211, 0x039F, 0x0281, 0x038E, 0x03AD, 0x033F, + 0x035D, 0x033E, 0x034E, 0x034F, 0x0212, 0x03BD, 0x032F, 0x035E, + 0x038F, 0x039E +}; + +static const uint16_t percentile_arr_8x5_1[167] { + 0x0621, 0xFCC2, 0x3443, 0xA433, 0x5532, 0x2551, 0x6CA3, 0x27AE, + 0x6452, 0x8E03, 0x3CB3, 0x4DA2, 0x6DDF, 0x37CD, 0x6F01, 0x1691, + 0x2E82, 0x27BE, 0x1513, 0x34D2, 0x1D22, 0x3E31, 0x2593, 0x2CB2, + 0x1C16, 0x374F, 0x0DD1, 0x2583, 0x6613, 0x0CD1, 0x0C35, 0x1462, + 0x3E81, 0x2612, 0x2C42, 0x3407, 0x14A2, 0x0E02, 0x1CF1, 0x0C06, + 0x17BD, 0x0F7D, 0x1D23, 0x35B1, 0x179F, 0x0D92, 0x0F5E, 0x1451, + 0x04B1, 0x1F6E, 0x0DEF, 0x0D31, 0x374E, 0x15C1, 0x0541, 0x2405, + 0x17AD, 0x0471, 0x1472, 0x0DFE, 0x0711, 0x0FDD, 0x0DFF, 0x0432, + 0x1D82, 0x0423, 0x0F6D, 0x07AF, 0x0F5F, 0x04C1, 0x1542, 0x0561, + 0x0DCF, 0x1D03, 0x1493, 0x0422, 0x0445, 0x0D12, 0x0C25, 0x0415, + 0x0DA1, 0x1591, 0x0DEE, 0x05DE, 0x0C31, 0x0491, 0x0441, 0x0D21, + 0x078D, 0x057D, 0x0C61, 0x0F3F, 0x0581, 0x0D6E, 0x0501, 0x0CA1, + 0x04E1, 0x0DFD, 0x057F, 0x0502, 0x0511, 0x0C82, 0x0483, 0x0C03, + 0x079D, 0x0402, 0x0DDD, 0x0611, 0x05AE, 0x0DCE, 0x056F, 0x0421, + 0x057E, 0x071F, 0x0DBF, 0x05BE, 0x0412, 0x059F, 0x054E, 0x077E, + 0x0C26, 0x05ED, 0x073D, 0x0601, 0x0492, 0x0453, 0x075D, 0x058E, + 0x0F2D, 0x05CD, 0x0571, 0x053E, 0x0692, 0x05BD, 0x054F, 0x055E, + 0x0411, 0x0F1D, 0x074D, 0x059E, 0x05AF, 0x070D, 0x053F, 0x058F, + 0x0413, 0x070F, 0x055D, 0x070E, 0x078F, 0x052E, 0x072F, 0x055F, + 0x078E, 0x0F2E, 0x052F, 0x051F, 0x0417, 0x071E, 0x0781, 0x0622, + 0x0683, 0x0702, 0x073E, 0x076F, 0x079E, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_8x5 { + 8, 5, + { 226, 167 }, + { 763, 517 }, + { 0, 178 }, + { percentile_arr_8x5_0, percentile_arr_8x5_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 6) +static const uint16_t percentile_arr_8x6_0[273] { + 0x0154, 0xF944, 0xE066, 0xA128, 0x9963, 0x8118, 0x806F, 0x79F2, + 0x79E2, 0x7108, 0xD934, 0x6056, 0x69C3, 0x60F3, 0x5972, 0x59E3, + 0x5075, 0x91B3, 0xC9D2, 0x807E, 0x385F, 0x4153, 0x3943, 0x4162, + 0x3837, 0x3847, 0x7173, 0x31D3, 0x6948, 0x3046, 0x307F, 0x5827, + 0x3114, 0x32C1, 0x3076, 0x2A4D, 0x58E3, 0x306E, 0x2924, 0x2A61, + 0x29F1, 0x50D3, 0x704F, 0x210C, 0x2BA1, 0x2225, 0x2873, 0x4865, + 0x2206, 0x8341, 0x2006, 0x3B21, 0x18F2, 0x21C2, 0x1A1F, 0x23C1, + 0x3AE1, 0x1855, 0x19D1, 0x1A15, 0x3815, 0x1207, 0x1835, 0x2A2E, + 0x1A16, 0x1836, 0x2271, 0x2845, 0x1A2D, 0x11E1, 0x1816, 0x1171, + 0x2217, 0x1952, 0x12D1, 0x3904, 0x125D, 0x4BB1, 0x207D, 0x10E2, + 0x1026, 0x2025, 0x12F1, 0x28F1, 0x105D, 0x1235, 0x12A2, 0x1007, + 0x123D, 0x1A05, 0x1072, 0x1331, 0x101E, 0x0951, 0x10D2, 0x1057, + 0x1B92, 0x185E, 0x1251, 0x19A2, 0x186D, 0x0B81, 0x2BEE, 0x080E, + 0x1A33, 0x1942, 0x0B13, 0x0B51, 0x11A3, 0x0923, 0x2322, 0x09B1, + 0x184E, 0x1161, 0x18D1, 0x0933, 0x0B93, 0x4A62, 0x1017, 0x082F, + 0x0A42, 0x0B82, 0x0AA3, 0x0A41, 0x08C2, 0x08B3, 0x0A3E, 0x22B3, + 0x0871, 0x1BBF, 0x09C1, 0x0AC2, 0x09B2, 0x0BEF, 0x082E, 0x1062, + 0x0922, 0x08C3, 0x1063, 0x0A53, 0x0BDF, 0x080F, 0x0B42, 0x0A83, + 0x084D, 0x103F, 0x0931, 0x08E1, 0x0A0F, 0x1BA2, 0x09FF, 0x1332, + 0x03FF, 0x0941, 0x12C3, 0x0A63, 0x003D, 0x0842, 0x083E, 0x0B83, + 0x0BB2, 0x0A31, 0x0932, 0x1102, 0x0992, 0x0982, 0x1051, 0x08B1, + 0x0A2F, 0x121E, 0x02B1, 0x0A4E, 0x11EE, 0x00A2, 0x1022, 0x0043, + 0x0A52, 0x0A1D, 0x0226, 0x1193, 0x03DD, 0x08B2, 0x0BFD, 0x0A43, + 0x0A13, 0x0AB2, 0x01FD, 0x09FE, 0x020D, 0x081F, 0x0B33, 0x0053, + 0x0B91, 0x0293, 0x0B11, 0x0B7F, 0x0AA1, 0x0B03, 0x0A0E, 0x03FE, + 0x01CE, 0x0B6F, 0x0183, 0x0912, 0x023F, 0x0852, 0x0A21, 0x0323, + 0x03ED, 0x0A32, 0x13AF, 0x0272, 0x08A3, 0x0B12, 0x0083, 0x0832, + 0x13CD, 0x0223, 0x0A92, 0x0092, 0x0AD2, 0x0301, 0x0302, 0x0BDE, + 0x0A22, 0x01EF, 0x0B5F, 0x0103, 0x0BCF, 0x096F, 0x017E, 0x0113, + 0x01DE, 0x0823, 0x0282, 0x0B6E, 0x015F, 0x0813, 0x01AF, 0x01CF, + 0x0B7E, 0x0033, 0x01DF, 0x0BCE, 0x01BF, 0x036D, 0x0A03, 0x017F, + 0x03BE, 0x0201, 0x0893, 0x038E, 0x034D, 0x03AE, 0x0202, 0x039F, + 0x0291, 0x0A11, 0x032E, 0x033F, 0x034F, 0x0281, 0x037D, 0x03BD, + 0x0212, 0x033E, 0x035E, 0x034E, 0x035D, 0x03AD, 0x032F, 0x038F, + 0x039E +}; + +static const uint16_t percentile_arr_8x6_1[186] { + 0x0621, 0xFC33, 0x37AE, 0x1CC2, 0x2C43, 0xAD32, 0x34A3, 0x4551, + 0x6452, 0x5C62, 0x1FCD, 0x14F1, 0x4CB3, 0x24D2, 0x15DF, 0x0FBE, + 0x2603, 0x3DA2, 0x2E31, 0x25D1, 0x25EF, 0x0D22, 0x2E91, 0x1E82, + 0x0FBD, 0x1513, 0x0CB2, 0x0CD1, 0x0F4F, 0x1F7D, 0x1701, 0x0C16, + 0x2593, 0x2C42, 0x0C72, 0x14A2, 0x0F6E, 0x0C35, 0x0C71, 0x0D83, + 0x0C07, 0x1DFF, 0x043E, 0x1613, 0x07DD, 0x0FAD, 0x1451, 0x076D, + 0x0E81, 0x05FE, 0x0406, 0x0E0D, 0x045D, 0x2612, 0x0E02, 0x07AF, + 0x0DB1, 0x0F5E, 0x15C1, 0x0C23, 0x1523, 0x0C1F, 0x0D92, 0x04B1, + 0x0D31, 0x0432, 0x0D61, 0x0F4E, 0x0D41, 0x0DEE, 0x0D42, 0x04C1, + 0x0CE1, 0x079F, 0x0C2E, 0x0405, 0x0C22, 0x0461, 0x0E1D, 0x0582, + 0x073F, 0x0571, 0x0C4D, 0x0DFD, 0x05CE, 0x0C6D, 0x05DE, 0x0415, + 0x0C45, 0x075F, 0x0C41, 0x0D03, 0x05A1, 0x0711, 0x05CF, 0x0425, + 0x0C93, 0x0D21, 0x0591, 0x043D, 0x0D12, 0x0501, 0x040F, 0x0511, + 0x0431, 0x0C03, 0x04A1, 0x078D, 0x0581, 0x041E, 0x040D, 0x0C02, + 0x040E, 0x05DD, 0x057F, 0x079D, 0x042D, 0x0D9F, 0x0502, 0x056E, + 0x0412, 0x071F, 0x044E, 0x05BF, 0x0C1D, 0x0482, 0x05AE, 0x042F, + 0x057D, 0x0491, 0x054E, 0x047D, 0x0DBE, 0x0611, 0x0492, 0x0601, + 0x05BD, 0x05CD, 0x0426, 0x05ED, 0x072D, 0x073D, 0x0483, 0x0F5D, + 0x0421, 0x056F, 0x053F, 0x058E, 0x054F, 0x078F, 0x053E, 0x059E, + 0x057E, 0x051F, 0x055D, 0x0413, 0x070D, 0x05AF, 0x0411, 0x0453, + 0x0D5E, 0x077E, 0x052F, 0x070F, 0x074D, 0x0692, 0x070E, 0x072F, + 0x072E, 0x058F, 0x071D, 0x052E, 0x0417, 0x073E, 0x0781, 0x078E, + 0x055F, 0x060E, 0x0622, 0x0683, 0x0702, 0x071E, 0x076F, 0x079E, + 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_8x6 { + 8, 6, + { 273, 186 }, + { 880, 300 }, + { 0, 64 }, + { percentile_arr_8x6_0, percentile_arr_8x6_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 8) +static const uint16_t percentile_arr_8x8_0[347] { + 0x0334, 0xFD44, 0xDD14, 0x9154, 0x9B08, 0x906A, 0x8928, 0x8108, + 0xE866, 0xC918, 0x606F, 0xC0FE, 0x5963, 0x58EE, 0x6534, 0x505A, + 0x51E2, 0xA8CF, 0x5354, 0x5314, 0x5134, 0x5524, 0x48F3, 0x504B, + 0x487E, 0x5344, 0x49C3, 0x4972, 0x49F2, 0x4856, 0xD0EF, 0x81D2, + 0x78DE, 0x4261, 0x3AC1, 0x71E3, 0x6879, 0x390C, 0x3143, 0x31B3, + 0x385F, 0x3153, 0x306E, 0x3037, 0x30DF, 0x3162, 0x304F, 0x3075, + 0xB03B, 0x2847, 0x28E3, 0x2914, 0x507F, 0x28BF, 0x5173, 0x5073, + 0x20D3, 0x2A06, 0x2827, 0x2508, 0x2229, 0x29D3, 0x204A, 0x207A, + 0x2046, 0x4148, 0x20FD, 0x4225, 0x23A1, 0x3944, 0x2065, 0x1924, + 0x2324, 0x1806, 0x19F1, 0x2215, 0x1876, 0x22AD, 0x502B, 0x1B04, + 0x18F2, 0x3A4D, 0x3216, 0x3504, 0x18DD, 0x1B21, 0x10CE, 0x1869, + 0x1B41, 0x1855, 0x1207, 0x1AE1, 0x2845, 0x19D1, 0x2A0A, 0x1A2D, + 0x2A1A, 0x11C2, 0x1A0B, 0x1217, 0x2816, 0x121B, 0x1271, 0x2AD1, + 0x1035, 0x1015, 0x287D, 0x12F1, 0x43C1, 0x1171, 0x1A05, 0x08E2, + 0x11E1, 0x3251, 0x2049, 0x20F1, 0x12CD, 0x0A39, 0x1219, 0x1059, + 0x1104, 0x1036, 0x1872, 0x3007, 0x08ED, 0x205E, 0x1026, 0x0952, + 0x1392, 0x1019, 0x0951, 0x100A, 0x13EE, 0x08D2, 0x1242, 0x0ABD, + 0x22A2, 0x0BDF, 0x2B81, 0x0A35, 0x13B1, 0x0839, 0x13BF, 0x0A33, + 0x1B31, 0x205D, 0x1241, 0x183A, 0x2025, 0x0B93, 0x0A3D, 0x1017, + 0x1313, 0x1253, 0x082A, 0x204E, 0x09A2, 0x080B, 0x0A1F, 0x125D, + 0x0A2E, 0x081A, 0x08D1, 0x082F, 0x086D, 0x1B82, 0x0A09, 0x0B22, + 0x1062, 0x11A3, 0x2161, 0x0923, 0x129F, 0x1A62, 0x0871, 0x0942, + 0x081B, 0x1133, 0x18AE, 0x0A9E, 0x0863, 0x09FF, 0x18C2, 0x0B51, + 0x08BD, 0x0AA3, 0x09B1, 0x1AC2, 0x08B3, 0x0829, 0x0BEF, 0x0B83, + 0x0AAE, 0x0A8D, 0x1857, 0x185B, 0x08AF, 0x103F, 0x08C3, 0x09B2, + 0x0A4E, 0x11C1, 0x0A31, 0x0B42, 0x0A83, 0x0BFF, 0x13DD, 0x00CD, + 0x0AB3, 0x0842, 0x08BE, 0x0922, 0x1A8E, 0x08E1, 0x002E, 0x0BA2, + 0x0A8F, 0x2263, 0x0252, 0x0B32, 0x0AC3, 0x0941, 0x0A43, 0x083D, + 0x083E, 0x0A3E, 0x084D, 0x1131, 0x136F, 0x0AB1, 0x0193, 0x0BFD, + 0x0391, 0x0851, 0x13AF, 0x0843, 0x0213, 0x1226, 0x0932, 0x03B2, + 0x0902, 0x0BCD, 0x0221, 0x089E, 0x00B1, 0x0BDE, 0x03FE, 0x02A1, + 0x0982, 0x009F, 0x080E, 0x0B5F, 0x02BE, 0x0A32, 0x0A2A, 0x01EE, + 0x0053, 0x0AB2, 0x0192, 0x09FD, 0x0052, 0x0B03, 0x0293, 0x00A2, + 0x0B7F, 0x0BED, 0x0311, 0x08B2, 0x0A72, 0x088E, 0x0333, 0x0B12, + 0x0A23, 0x0822, 0x0083, 0x11CE, 0x021D, 0x08A3, 0x088F, 0x029D, + 0x0A22, 0x0A3F, 0x01FE, 0x020F, 0x0983, 0x02D2, 0x0292, 0x0B23, + 0x001E, 0x0BCF, 0x03CE, 0x09AF, 0x0B02, 0x0301, 0x022F, 0x137E, + 0x021E, 0x09EF, 0x016F, 0x0112, 0x097E, 0x080F, 0x020D, 0x0092, + 0x01DE, 0x09DF, 0x0032, 0x0033, 0x0A82, 0x03BE, 0x0B6E, 0x001F, + 0x020E, 0x0023, 0x09CF, 0x0113, 0x0103, 0x0013, 0x0BAE, 0x0203, + 0x0BAD, 0x01BF, 0x034F, 0x095F, 0x036D, 0x0202, 0x017F, 0x0093, + 0x0201, 0x034D, 0x0212, 0x035D, 0x03BD, 0x0B3F, 0x035E, 0x0211, + 0x0281, 0x0291, 0x032E, 0x037D, 0x034E, 0x038E, 0x039F, 0x032F, + 0x033E, 0x038F, 0x039E +}; + +static const uint16_t percentile_arr_8x8_1[208] { + 0x0621, 0x3443, 0x47CD, 0x97AE, 0xFC62, 0x14F1, 0x24C2, 0x25DF, + 0x3C33, 0x1C52, 0x9C72, 0x0FBE, 0x0C5D, 0x343E, 0x24A3, 0x1551, + 0x5D32, 0x1CD2, 0x15EF, 0x4E31, 0x04DD, 0x1FDD, 0x174F, 0x0DD1, + 0x3E0D, 0x15FF, 0x0DA2, 0x1E03, 0x17BD, 0x177D, 0x14B3, 0x0471, + 0x0CAE, 0x1C1F, 0x04D1, 0x0F6E, 0x0DFE, 0x1C42, 0x0C16, 0x0D22, + 0x0C9F, 0x2C2E, 0x0FAD, 0x0571, 0x147D, 0x0C07, 0x04B2, 0x0F6D, + 0x0F5E, 0x07AF, 0x146D, 0x0C51, 0x0593, 0x2583, 0x0C4E, 0x040B, + 0x0C35, 0x0513, 0x0E91, 0x0406, 0x073F, 0x144D, 0x0561, 0x048F, + 0x0F01, 0x0F4E, 0x0CA2, 0x075F, 0x1682, 0x04E1, 0x0C1A, 0x04BD, + 0x0542, 0x0D41, 0x0DEE, 0x04CD, 0x0DCF, 0x04B1, 0x0C15, 0x0C3D, + 0x0423, 0x0592, 0x0DDE, 0x0422, 0x0432, 0x05FD, 0x0DC1, 0x05B1, + 0x0DCE, 0x0612, 0x0C2F, 0x0445, 0x0602, 0x0531, 0x0439, 0x0E81, + 0x0582, 0x0C61, 0x061D, 0x049E, 0x0405, 0x0409, 0x0DBE, 0x079F, + 0x0D21, 0x04C1, 0x0C0A, 0x0E13, 0x04AD, 0x040E, 0x0581, 0x0419, + 0x05DD, 0x0D03, 0x049D, 0x0449, 0x0429, 0x048E, 0x0DA1, 0x0425, + 0x0512, 0x0501, 0x0431, 0x0523, 0x0441, 0x042D, 0x040F, 0x0D7D, + 0x0511, 0x0502, 0x05BF, 0x04A1, 0x0C03, 0x0402, 0x079D, 0x05AE, + 0x075D, 0x057F, 0x041D, 0x048D, 0x042A, 0x0453, 0x05AF, 0x078D, + 0x0C0D, 0x073D, 0x0491, 0x0591, 0x05BD, 0x072D, 0x057E, 0x051F, + 0x0482, 0x0492, 0x041E, 0x0412, 0x0D9F, 0x0421, 0x0493, 0x0711, + 0x056E, 0x059E, 0x054E, 0x0611, 0x05ED, 0x074D, 0x070F, 0x056F, + 0x052F, 0x053F, 0x071F, 0x054F, 0x05CD, 0x0483, 0x055E, 0x072F, + 0x0E01, 0x0426, 0x058F, 0x0413, 0x078F, 0x071D, 0x055F, 0x058E, + 0x0411, 0x053E, 0x071E, 0x055D, 0x077E, 0x052E, 0x0692, 0x0417, + 0x070D, 0x078E, 0x070E, 0x072E, 0x041B, 0x060E, 0x0622, 0x0683, + 0x068D, 0x0702, 0x073E, 0x076F, 0x0781, 0x079E, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_8x8 { + 8, 8, + { 347, 208 }, + { 1144, 267 }, + { 0, 38 }, + { percentile_arr_8x8_0, percentile_arr_8x8_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 5) +static const uint16_t percentile_arr_10x5_0[274] { + 0x0165, 0xF975, 0xD866, 0xC056, 0xA946, 0x90C6, 0x90F5, 0x8963, + 0x80D6, 0x80E6, 0x60F3, 0x61C3, 0x59F2, 0xA927, 0x5075, 0x4847, + 0x5153, 0x4955, 0x49E2, 0x48B6, 0x41D2, 0x4943, 0x8305, 0x8172, + 0x4046, 0x4037, 0x40A7, 0x70B7, 0x7AC1, 0x31E3, 0x7027, 0x30E5, + 0x69D3, 0x99B3, 0x3315, 0x6115, 0x3136, 0x3076, 0x3173, 0x30D5, + 0x3106, 0x8962, 0x2916, 0x30C7, 0x5126, 0x30D3, 0x2956, 0x5117, + 0x2B41, 0x2AE1, 0x2A61, 0x29F1, 0x2306, 0x2145, 0x4A85, 0x2057, + 0x40E3, 0x4137, 0x3B21, 0x23C1, 0x2065, 0x1925, 0x51C2, 0x5225, + 0x4935, 0x1AD1, 0x23A1, 0x19D1, 0x1A71, 0x4055, 0x1873, 0x1A86, + 0x1295, 0x18F2, 0x28A6, 0x1952, 0x4AA5, 0x20B5, 0x10C5, 0x2AA2, + 0x11E1, 0x1107, 0x10D2, 0x2171, 0x1351, 0x3036, 0x1331, 0x1BEE, + 0x2035, 0x1045, 0x1313, 0x0A15, 0x1087, 0x1296, 0x13EF, 0x18E2, + 0x1151, 0x1086, 0x10F1, 0x08A5, 0x12C2, 0x1BFF, 0x1095, 0x1A62, + 0x1322, 0x0942, 0x1026, 0x1872, 0x1062, 0x0897, 0x1123, 0x08D1, + 0x1A06, 0x0806, 0x137F, 0x13B1, 0x13DF, 0x1A51, 0x09B1, 0x0A83, + 0x1015, 0x22F1, 0x0961, 0x0B81, 0x12B3, 0x0A35, 0x0AA3, 0x20B3, + 0x08C3, 0x2342, 0x0933, 0x0A33, 0x09A2, 0x10C2, 0x0896, 0x2205, + 0x0825, 0x20E1, 0x0922, 0x1242, 0x0B16, 0x0B32, 0x09A3, 0x0AC3, + 0x0BBF, 0x0B93, 0x0071, 0x0931, 0x0A41, 0x2392, 0x13FE, 0x09C1, + 0x0B07, 0x0016, 0x1182, 0x09B2, 0x0A26, 0x0132, 0x0941, 0x0A93, + 0x0992, 0x1063, 0x1217, 0x01FF, 0x11EE, 0x1216, 0x0B23, 0x0B82, + 0x0042, 0x1102, 0x0213, 0x0B6F, 0x09FE, 0x1207, 0x0807, 0x18B1, + 0x0253, 0x0AB1, 0x08A2, 0x13FD, 0x01FD, 0x1983, 0x0AB2, 0x0A31, + 0x016F, 0x0B11, 0x00B2, 0x0851, 0x0AD2, 0x0993, 0x0BDD, 0x12A1, + 0x017F, 0x0A97, 0x1022, 0x0383, 0x0843, 0x0A52, 0x03A2, 0x097E, + 0x0817, 0x03B2, 0x0A43, 0x09EF, 0x0A63, 0x0B33, 0x0B03, 0x0292, + 0x0272, 0x09CE, 0x0287, 0x136D, 0x0053, 0x0B12, 0x0083, 0x0892, + 0x0112, 0x1282, 0x03ED, 0x0852, 0x0301, 0x1391, 0x0232, 0x0B7E, + 0x0221, 0x08A3, 0x0BCD, 0x0BCF, 0x036E, 0x09DE, 0x0103, 0x03DE, + 0x0832, 0x0BAF, 0x0302, 0x13CE, 0x035F, 0x0093, 0x0A23, 0x01DF, + 0x0013, 0x0A22, 0x0023, 0x0113, 0x09AF, 0x01BF, 0x0033, 0x095F, + 0x0203, 0x0281, 0x09CF, 0x037D, 0x0201, 0x0B4D, 0x03AE, 0x03BE, + 0x0291, 0x035E, 0x038E, 0x0B9F, 0x03AD, 0x0202, 0x034F, 0x0211, + 0x035D, 0x0212, 0x032E, 0x039E, 0x033F, 0x034E, 0x03BD, 0x032F, + 0x033E, 0x038F +}; + +static const uint16_t percentile_arr_10x5_1[180] { + 0x0532, 0xFCA3, 0x3621, 0x6E82, 0x2CC2, 0x3D51, 0x3F01, 0x2691, + 0x17AE, 0x35A2, 0x74B3, 0x1603, 0x4433, 0x3C43, 0x6C35, 0x25D1, + 0x1D13, 0x15DF, 0x37CD, 0x0D93, 0x1D22, 0x0E81, 0x1452, 0x0CD2, + 0x37BE, 0x0CB2, 0x3407, 0x1523, 0x0C16, 0x0CB5, 0x0C96, 0x1486, + 0x2631, 0x1506, 0x0F4F, 0x1583, 0x0CD1, 0x2CA2, 0x2612, 0x1613, + 0x1602, 0x1F11, 0x179F, 0x17BD, 0x15B1, 0x0406, 0x1D41, 0x0CF1, + 0x0D31, 0x0442, 0x1C62, 0x0F6E, 0x077D, 0x0C51, 0x0445, 0x0D15, + 0x2592, 0x0CB1, 0x05EF, 0x0542, 0x17AF, 0x1425, 0x075E, 0x0FAD, + 0x0CC1, 0x0503, 0x0512, 0x15C1, 0x0C95, 0x0415, 0x0505, 0x0F4E, + 0x04A5, 0x0493, 0x0C32, 0x0F5F, 0x04E1, 0x0521, 0x0C85, 0x07DD, + 0x0582, 0x15FF, 0x05CF, 0x0405, 0x0D91, 0x05A1, 0x05FE, 0x0C23, + 0x0561, 0x0472, 0x0471, 0x0C22, 0x0DEE, 0x076D, 0x0502, 0x0426, + 0x0C61, 0x0D7D, 0x0525, 0x05DE, 0x0DCE, 0x079D, 0x0692, 0x0441, + 0x0C91, 0x05DD, 0x0511, 0x057F, 0x0611, 0x0DFD, 0x078D, 0x056E, + 0x0492, 0x04A1, 0x073F, 0x0C31, 0x05BE, 0x0483, 0x0571, 0x056F, + 0x0D9F, 0x0581, 0x0501, 0x057E, 0x05BF, 0x078F, 0x0516, 0x05ED, + 0x0402, 0x0F7E, 0x0482, 0x054E, 0x075D, 0x071F, 0x05CD, 0x0535, + 0x05AE, 0x0C11, 0x058F, 0x05AF, 0x0421, 0x0413, 0x0601, 0x054F, + 0x073D, 0x059E, 0x0487, 0x070F, 0x078E, 0x0781, 0x053E, 0x0403, + 0x072D, 0x055D, 0x05BD, 0x079E, 0x0D8E, 0x0412, 0x052E, 0x074D, + 0x053F, 0x051F, 0x070E, 0x055F, 0x072F, 0x052F, 0x070D, 0x055E, + 0x0417, 0x0453, 0x072E, 0x0622, 0x0683, 0x0702, 0x071D, 0x071E, + 0x073E, 0x076F, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_10x5 { + 10, 5, + { 274, 180 }, + { 954, 324 }, + { 0, 79 }, + { percentile_arr_10x5_0, percentile_arr_10x5_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 6) +static const uint16_t percentile_arr_10x6_0[325] { + 0x01A4, 0xF954, 0xA066, 0x9975, 0x80F5, 0x7056, 0x6918, 0x6963, + 0x58C6, 0x5946, 0x5928, 0x5174, 0x586F, 0xA0E6, 0x5108, 0x48D6, + 0x49E2, 0x40F3, 0x9172, 0x41F2, 0xB875, 0x3927, 0x39C3, 0xA953, + 0x3934, 0x3305, 0x30B6, 0x6943, 0x31D2, 0x3876, 0x3037, 0x2955, + 0x30A7, 0x32C1, 0x29B3, 0x3027, 0x287E, 0x30B7, 0x29E3, 0x5846, + 0x2B15, 0x2847, 0x3162, 0x5173, 0x4936, 0x285F, 0x48D3, 0x2164, + 0x4906, 0x20E5, 0x2915, 0x2116, 0x407F, 0x20D5, 0x2A61, 0x4117, + 0x20E3, 0x2126, 0x4148, 0x206E, 0x39D3, 0x2145, 0x41B4, 0x1B06, + 0x2114, 0x2165, 0x5321, 0x5A85, 0x1A4D, 0x1A1F, 0x19F1, 0x3341, + 0x184F, 0x1956, 0x3125, 0x30C7, 0x28F2, 0x1937, 0x1AE1, 0x1073, + 0x1BA1, 0x1935, 0x110C, 0x1BC1, 0x3A25, 0x19C2, 0x1295, 0x122E, + 0x1944, 0x11D1, 0x1124, 0x1857, 0x22D1, 0x2286, 0x1A2D, 0x12A2, + 0x2107, 0x1055, 0x2065, 0x0A71, 0x2152, 0x10C5, 0x10D2, 0x1331, + 0x08B5, 0x1171, 0x2836, 0x10A6, 0x0904, 0x123D, 0x20F1, 0x12A5, + 0x10E2, 0x107D, 0x1AF1, 0x1313, 0x0951, 0x11E1, 0x1B22, 0x1B51, + 0x0835, 0x101E, 0x0A5D, 0x0A15, 0x3045, 0x0A96, 0x08A5, 0x1142, + 0x12A3, 0x1872, 0x085D, 0x09B1, 0x100E, 0x0887, 0x0886, 0x086D, + 0x0933, 0x12B3, 0x0897, 0x08B3, 0x0A33, 0x0923, 0x1095, 0x0BEE, + 0x2BB1, 0x085E, 0x1283, 0x0A51, 0x1026, 0x0A06, 0x12C2, 0x08D1, + 0x11A2, 0x13BF, 0x08C3, 0x10C2, 0x0A3E, 0x0BDF, 0x0B81, 0x13EF, + 0x0A35, 0x0B16, 0x082F, 0x2161, 0x1B32, 0x0806, 0x084E, 0x11A3, + 0x1015, 0x1122, 0x2931, 0x0342, 0x0825, 0x0A0F, 0x0896, 0x0A05, + 0x0241, 0x09C1, 0x083F, 0x0A42, 0x0071, 0x0B07, 0x082E, 0x0393, + 0x12B1, 0x0A62, 0x0226, 0x0A2F, 0x0B92, 0x0063, 0x0932, 0x0862, + 0x09FF, 0x0A31, 0x00E1, 0x12B2, 0x09B2, 0x0AC3, 0x0941, 0x0293, + 0x1323, 0x104D, 0x003E, 0x083D, 0x0992, 0x1382, 0x03FF, 0x0A13, + 0x1016, 0x0A53, 0x0182, 0x1007, 0x0AA1, 0x080F, 0x0A16, 0x0A1E, + 0x0042, 0x0902, 0x13DD, 0x0BB2, 0x0A63, 0x00A2, 0x08B1, 0x03FE, + 0x1207, 0x08B2, 0x0B83, 0x09EE, 0x0311, 0x0A87, 0x0BAF, 0x03A2, + 0x09FD, 0x0051, 0x0B33, 0x020D, 0x09CE, 0x0217, 0x021D, 0x0817, + 0x020E, 0x0A4E, 0x001F, 0x0BFD, 0x0297, 0x0983, 0x0A92, 0x0252, + 0x0243, 0x0B03, 0x0193, 0x036F, 0x0B12, 0x0043, 0x0822, 0x0A21, + 0x01FE, 0x0853, 0x037F, 0x023F, 0x0BED, 0x02D2, 0x0B91, 0x0232, + 0x0282, 0x0912, 0x08A3, 0x0852, 0x0223, 0x0BCD, 0x0083, 0x0301, + 0x0832, 0x01EF, 0x0892, 0x0302, 0x0A72, 0x03DE, 0x0893, 0x0BCF, + 0x09DE, 0x03CE, 0x035F, 0x0833, 0x0023, 0x0103, 0x017E, 0x0813, + 0x01CF, 0x01BF, 0x016F, 0x0A22, 0x037E, 0x0113, 0x01AF, 0x0B6E, + 0x03BE, 0x0201, 0x0A03, 0x01DF, 0x036D, 0x03AE, 0x015F, 0x0281, + 0x033E, 0x0A02, 0x038E, 0x017F, 0x0291, 0x034D, 0x03BD, 0x0B7D, + 0x03AD, 0x0211, 0x0212, 0x034F, 0x032E, 0x039F, 0x034E, 0x035D, + 0x035E, 0x033F, 0x039E, 0x032F, 0x038F +}; + +static const uint16_t percentile_arr_10x6_1[199] { + 0x0621, 0xBD32, 0x5CA3, 0x1FAE, 0x64C2, 0x1D51, 0x6C33, 0xFC43, + 0x5CB3, 0x25A2, 0x2E82, 0x35D1, 0x4F01, 0x3FBE, 0x3691, 0x2DDF, + 0x2E03, 0x3FCD, 0x14D2, 0x1CF1, 0x0C52, 0x3C35, 0x2D22, 0x1513, + 0x1462, 0x54B2, 0x0E31, 0x4E81, 0x1593, 0x1D23, 0x1CD1, 0x14B5, + 0x2FBD, 0x0C07, 0x1D06, 0x0DEF, 0x14A2, 0x1612, 0x1F4F, 0x0C16, + 0x1F7D, 0x0C96, 0x0486, 0x1F9F, 0x0D42, 0x4583, 0x0E02, 0x0472, + 0x0DB1, 0x1613, 0x0FAD, 0x0D41, 0x0F11, 0x0E0D, 0x1C42, 0x143E, + 0x076E, 0x04B1, 0x0FAF, 0x0D61, 0x0531, 0x0C71, 0x0DFF, 0x0DFE, + 0x0406, 0x0C45, 0x0451, 0x0D15, 0x05C1, 0x2CC1, 0x141F, 0x0CE1, + 0x0FDD, 0x0C22, 0x0582, 0x0D92, 0x0571, 0x0F6D, 0x0C93, 0x045D, + 0x0F5E, 0x044D, 0x0423, 0x0D05, 0x0425, 0x0C95, 0x04A5, 0x0DCE, + 0x075F, 0x0E1D, 0x0503, 0x042E, 0x0D91, 0x0512, 0x0DDE, 0x05A1, + 0x074E, 0x0C32, 0x0431, 0x0415, 0x0D21, 0x05EE, 0x040E, 0x0DDD, + 0x0485, 0x1525, 0x0491, 0x0C26, 0x046D, 0x0C05, 0x05CF, 0x05FD, + 0x0E92, 0x073F, 0x0C0D, 0x043D, 0x0502, 0x0C1E, 0x041D, 0x0461, + 0x04A1, 0x0511, 0x0581, 0x05BD, 0x0C41, 0x059F, 0x05BF, 0x040F, + 0x0C7D, 0x0402, 0x054E, 0x057D, 0x0403, 0x078D, 0x05AE, 0x042D, + 0x0483, 0x079D, 0x0D7F, 0x0482, 0x0611, 0x056E, 0x0516, 0x05BE, + 0x0535, 0x044E, 0x05AF, 0x0DED, 0x042F, 0x0492, 0x058E, 0x078F, + 0x0412, 0x057E, 0x053E, 0x0F1F, 0x073D, 0x0601, 0x0501, 0x075D, + 0x059E, 0x05CD, 0x053F, 0x054F, 0x055E, 0x055D, 0x0421, 0x074D, + 0x051F, 0x072F, 0x0781, 0x0411, 0x0D6F, 0x077E, 0x0487, 0x070E, + 0x070F, 0x072D, 0x058F, 0x078E, 0x079E, 0x052E, 0x0413, 0x072E, + 0x071D, 0x052F, 0x055F, 0x073E, 0x0417, 0x0453, 0x060E, 0x0622, + 0x0683, 0x0702, 0x070D, 0x071E, 0x076F, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_10x6 { + 10, 6, + { 325, 199 }, + { 922, 381 }, + { 0, 78 }, + { percentile_arr_10x6_0, percentile_arr_10x6_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 8) +static const uint16_t percentile_arr_10x8_0[400] { + 0x0154, 0xAB34, 0xAD44, 0x8308, 0x7866, 0x7B64, 0x79A4, 0x7975, + 0x686A, 0x6908, 0xC514, 0x6174, 0x6128, 0x6118, 0x5B54, 0x5163, + 0xF856, 0x50F5, 0x986F, 0xDD34, 0x48FE, 0x4972, 0x48E6, 0x4146, + 0x48EE, 0x40F3, 0x4AC1, 0x38C6, 0x41E2, 0xBB05, 0x707E, 0x38D6, + 0x3927, 0x6B14, 0x384B, 0x3948, 0x3153, 0x385A, 0x3134, 0x6B15, + 0x39F2, 0x30CF, 0x3143, 0x91D2, 0x31C3, 0x60EF, 0x5973, 0x3076, + 0x28D3, 0x3261, 0x2875, 0x28DE, 0x290C, 0x51E3, 0x28A7, 0x20E3, + 0x2962, 0x2B06, 0x2917, 0x483B, 0x20B6, 0x2D24, 0x206E, 0x285F, + 0x20B7, 0x2936, 0x4047, 0x2037, 0x20DF, 0x28BF, 0x21B4, 0x21B3, + 0x1D08, 0x2027, 0x404F, 0x3846, 0x2116, 0x187F, 0x1879, 0x2285, + 0x1A29, 0x3915, 0x4873, 0x1955, 0x3114, 0x1B44, 0x2165, 0x107A, + 0x1956, 0x6137, 0x1106, 0x3145, 0x1B21, 0x19D3, 0x12AD, 0x1B41, + 0x1AD1, 0x1126, 0x18F2, 0x282B, 0x40E5, 0x20D5, 0x2A0A, 0x284A, + 0x1286, 0x1295, 0x121A, 0x2A0B, 0x321B, 0x122D, 0x10FD, 0x13A1, + 0x32A2, 0x12E1, 0x1164, 0x13C1, 0x124D, 0x1239, 0x4504, 0x10C7, + 0x22F1, 0x11F1, 0x0AC2, 0x2125, 0x1225, 0x0B04, 0x1107, 0x1069, + 0x1A19, 0x13BF, 0x2A96, 0x08D2, 0x1271, 0x0952, 0x2BDF, 0x0B31, + 0x1251, 0x2124, 0x0B13, 0x12BD, 0x1233, 0x13EE, 0x2144, 0x0B16, + 0x0A15, 0x18E2, 0x08DD, 0x1097, 0x0857, 0x0B24, 0x0AA5, 0x12A3, + 0x11C2, 0x11D1, 0x10CE, 0x0865, 0x123D, 0x08B3, 0x0B51, 0x1971, + 0x0A41, 0x0A06, 0x1039, 0x080A, 0x0B22, 0x0923, 0x0836, 0x08C3, + 0x0A1F, 0x1072, 0x080B, 0x0935, 0x0855, 0x18A6, 0x0A42, 0x1133, + 0x0A83, 0x0A09, 0x0ACD, 0x0A2E, 0x0887, 0x083A, 0x10C5, 0x085E, + 0x13B1, 0x087D, 0x0819, 0x0A9F, 0x0049, 0x08F1, 0x0BEF, 0x1161, + 0x0B42, 0x09E1, 0x0A05, 0x0904, 0x12AE, 0x029E, 0x0A31, 0x09FF, + 0x0951, 0x0859, 0x001A, 0x082F, 0x0B81, 0x08B5, 0x0A35, 0x082A, + 0x08ED, 0x1142, 0x1262, 0x0B32, 0x08A5, 0x12D2, 0x03DD, 0x0B07, + 0x18AE, 0x083F, 0x00AF, 0x0AB3, 0x086D, 0x0287, 0x0A93, 0x025D, + 0x0816, 0x13FF, 0x0A8D, 0x005D, 0x08D1, 0x0392, 0x0845, 0x0AC3, + 0x08C2, 0x01A3, 0x0AB1, 0x09A2, 0x005B, 0x0B93, 0x02B2, 0x1086, + 0x001B, 0x0863, 0x0216, 0x0AA1, 0x0896, 0x0A8F, 0x084E, 0x0A8E, + 0x0A53, 0x0026, 0x0A26, 0x0382, 0x0807, 0x0862, 0x0029, 0x0871, + 0x00BD, 0x0835, 0x024E, 0x0806, 0x0941, 0x0895, 0x03AF, 0x0A13, + 0x0932, 0x03ED, 0x0BFD, 0x0207, 0x0B83, 0x0993, 0x09B1, 0x03CD, + 0x0A3E, 0x03FE, 0x0A21, 0x0015, 0x0B11, 0x0A43, 0x00E1, 0x136F, + 0x00BE, 0x00A2, 0x0842, 0x0043, 0x0825, 0x082E, 0x0A2A, 0x03DE, + 0x0BA2, 0x0122, 0x0BCF, 0x004D, 0x0323, 0x09C1, 0x0292, 0x083E, + 0x0252, 0x0017, 0x0A72, 0x00CD, 0x0182, 0x0A63, 0x0131, 0x09B2, + 0x0303, 0x0902, 0x0053, 0x035F, 0x0A32, 0x003D, 0x0992, 0x0A2F, + 0x03B2, 0x0ABE, 0x009F, 0x0183, 0x0312, 0x08B1, 0x0B02, 0x0A17, + 0x0B7F, 0x0333, 0x0297, 0x0A23, 0x020F, 0x0282, 0x0851, 0x0822, + 0x03CE, 0x01EE, 0x000E, 0x08B2, 0x0083, 0x0A1D, 0x00A3, 0x0222, + 0x088F, 0x0112, 0x029D, 0x0092, 0x0A3F, 0x0391, 0x089E, 0x0301, + 0x01FD, 0x09BF, 0x01CE, 0x0852, 0x01FE, 0x0013, 0x0903, 0x088E, + 0x037E, 0x021E, 0x01EF, 0x095F, 0x016F, 0x09DE, 0x03BE, 0x020E, + 0x0113, 0x01DF, 0x080F, 0x020D, 0x0833, 0x03AE, 0x0032, 0x03BD, + 0x0823, 0x001E, 0x01AF, 0x0203, 0x034F, 0x0093, 0x0A81, 0x036E, + 0x0291, 0x038E, 0x0A01, 0x001F, 0x017F, 0x01CF, 0x017E, 0x0202, + 0x0BAD, 0x0211, 0x035D, 0x035E, 0x039F, 0x0212, 0x032E, 0x033F, + 0x034D, 0x034E, 0x036D, 0x032F, 0x033E, 0x037D, 0x038F, 0x039E +}; + +static const uint16_t percentile_arr_10x8_1[221] { + 0x0621, 0xDFAE, 0x2443, 0x54C2, 0x37CD, 0x1CF1, 0xFCA3, 0x14D2, + 0x2D32, 0x5551, 0x7DDF, 0x5C33, 0x15D1, 0x3462, 0x24B3, 0x7452, + 0x5FBE, 0x6472, 0x65A2, 0x1D06, 0x445D, 0x15EF, 0x0E31, 0x1D71, + 0x343E, 0x0D42, 0x0CDD, 0x1F01, 0x4691, 0x1435, 0x0E82, 0x0DFF, + 0x17DD, 0x0D22, 0x24B2, 0x1603, 0x04B5, 0x24AE, 0x060D, 0x2D13, + 0x0C7D, 0x0496, 0x17BD, 0x1F4F, 0x1F7D, 0x1486, 0x0593, 0x1C16, + 0x0C07, 0x15FE, 0x041F, 0x14D1, 0x0C9F, 0x0E81, 0x0D15, 0x27AF, + 0x0C2E, 0x0D23, 0x176E, 0x0FAD, 0x1C06, 0x1561, 0x0DB1, 0x040B, + 0x1C4E, 0x0D83, 0x1711, 0x0C42, 0x0C71, 0x1C1A, 0x0D25, 0x04A2, + 0x0C45, 0x076D, 0x0F9F, 0x075F, 0x0E12, 0x046D, 0x048F, 0x1D92, + 0x0602, 0x0C39, 0x174E, 0x0C51, 0x0CA1, 0x075E, 0x05C1, 0x14BD, + 0x0D31, 0x0423, 0x0F3F, 0x0495, 0x0C93, 0x049E, 0x0D05, 0x04E1, + 0x0DEE, 0x0415, 0x04B1, 0x0503, 0x0CCD, 0x042F, 0x0DCF, 0x044D, + 0x0541, 0x1582, 0x05DE, 0x0D01, 0x0487, 0x040A, 0x0516, 0x0CA5, + 0x05FD, 0x05BF, 0x057D, 0x0DA1, 0x0426, 0x040F, 0x071F, 0x0613, + 0x0432, 0x0D12, 0x043D, 0x0425, 0x0461, 0x061D, 0x0D21, 0x0591, + 0x079D, 0x048D, 0x0429, 0x0C49, 0x04C1, 0x042A, 0x040E, 0x0485, + 0x0511, 0x0405, 0x0502, 0x0441, 0x0C19, 0x0692, 0x0535, 0x058F, + 0x041D, 0x059F, 0x072D, 0x04AD, 0x049D, 0x05CE, 0x048E, 0x0C31, + 0x057F, 0x078D, 0x0409, 0x041E, 0x05AE, 0x0611, 0x058E, 0x05DD, + 0x05CD, 0x056E, 0x0483, 0x073D, 0x054E, 0x0D9E, 0x0402, 0x0491, + 0x040D, 0x056F, 0x042D, 0x0581, 0x0421, 0x057E, 0x0781, 0x053E, + 0x0482, 0x078F, 0x0413, 0x052E, 0x0601, 0x0422, 0x0492, 0x055E, + 0x05BE, 0x0F9E, 0x072F, 0x074D, 0x0412, 0x070F, 0x075D, 0x05BD, + 0x051F, 0x071D, 0x073E, 0x077E, 0x0403, 0x0411, 0x078E, 0x055D, + 0x05AF, 0x05ED, 0x052F, 0x053F, 0x070D, 0x070E, 0x072E, 0x054F, + 0x0417, 0x041B, 0x0453, 0x055F, 0x060E, 0x0622, 0x0683, 0x068D, + 0x0702, 0x071E, 0x076F, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_10x8 = +{ + 10, 8, + { 400, 221 }, + { 1119, 376 }, + { 0, 52 }, + { percentile_arr_10x8_0, percentile_arr_10x8_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 10) +static const uint16_t percentile_arr_10x10_0[453] { + 0x0334, 0x9514, 0x8954, 0x806A, 0x6F14, 0x6724, 0x6108, 0x6364, + 0x5175, 0x5D44, 0x5866, 0x5118, 0x5308, 0xA179, 0x5128, 0xF534, + 0x49A4, 0x5354, 0x9174, 0x486F, 0x48EA, 0x40F3, 0x4963, 0x414A, + 0xF8F9, 0x3984, 0x4172, 0x387E, 0x405A, 0x38DA, 0x38F5, 0x9B05, + 0x30EE, 0x32C1, 0x3261, 0x3D08, 0x31E2, 0x3056, 0x292B, 0x3146, + 0x3127, 0x3315, 0x58CA, 0x58E6, 0x290C, 0x3314, 0x8134, 0x28E3, + 0x28FE, 0x2948, 0x28C6, 0x78DE, 0x28BB, 0x68D6, 0x286E, 0x2173, + 0x2962, 0x21D2, 0x205F, 0x49F2, 0x2917, 0x2306, 0x207F, 0x404F, + 0x2153, 0x2943, 0x20CF, 0x21C3, 0x2073, 0x20D3, 0x2136, 0x183B, + 0x430A, 0x40A7, 0x18B6, 0x2079, 0x2309, 0x2075, 0x184B, 0x20EF, + 0x187A, 0x7837, 0x1B19, 0x20AB, 0x18BA, 0x20B7, 0x1994, 0x19E3, + 0x21B4, 0x49B3, 0x38BF, 0x193B, 0x1876, 0x182B, 0x30F2, 0x193A, + 0x1827, 0x1965, 0x1914, 0x184A, 0x4047, 0x1916, 0x1285, 0x1937, + 0x122D, 0x1915, 0x1321, 0x1955, 0x1046, 0x191B, 0x2106, 0x2919, + 0x1344, 0x1524, 0x12E1, 0x3926, 0x10E5, 0x2295, 0x1159, 0x1145, + 0x10DF, 0x124D, 0x1271, 0x092A, 0x2169, 0x1704, 0x22A2, 0x1164, + 0x13EE, 0x12F1, 0x0AD1, 0x128A, 0x110A, 0x11D3, 0x1286, 0x115A, + 0x2BA1, 0x0BBF, 0x3956, 0x2A89, 0x12AD, 0x10E9, 0x0B41, 0x1A29, + 0x2225, 0x08FD, 0x1107, 0x08D5, 0x191A, 0x1125, 0x1A96, 0x0B04, + 0x18D9, 0x2B16, 0x11F1, 0x0A33, 0x0924, 0x131A, 0x1149, 0x1324, + 0x0BEF, 0x0A99, 0x08CB, 0x123D, 0x1331, 0x0BDF, 0x0872, 0x22A3, + 0x0AC2, 0x1144, 0x0D04, 0x08D2, 0x08CE, 0x0AA9, 0x0A9A, 0x0B13, + 0x1251, 0x0865, 0x1069, 0x0897, 0x1215, 0x18B3, 0x1A62, 0x08C7, + 0x185E, 0x10E2, 0x0AA5, 0x21FF, 0x090B, 0x0952, 0x09E1, 0x0A42, + 0x08F1, 0x0A06, 0x0B22, 0x087D, 0x1139, 0x021F, 0x122E, 0x082F, + 0x09C2, 0x0887, 0x0A0A, 0x03C1, 0x0929, 0x0A5D, 0x0A83, 0x0BFF, + 0x0935, 0x085B, 0x0104, 0x08DD, 0x0923, 0x083F, 0x0241, 0x09D1, + 0x0A39, 0x0863, 0x0A8B, 0x08A6, 0x008B, 0x1133, 0x13B1, 0x089B, + 0x0AB3, 0x0036, 0x0BDD, 0x08ED, 0x0857, 0x0971, 0x0219, 0x1235, + 0x0AB1, 0x0ACD, 0x036F, 0x0A31, 0x08AA, 0x003A, 0x08C3, 0x0A05, + 0x02BD, 0x0B92, 0x0B07, 0x12B2, 0x08C5, 0x0B51, 0x0381, 0x0A8D, + 0x01A3, 0x0896, 0x0855, 0x0BFD, 0x005D, 0x0BFE, 0x023E, 0x08AF, + 0x00B9, 0x0A93, 0x00B5, 0x0862, 0x0A0B, 0x0A09, 0x0A72, 0x0332, + 0x0AA1, 0x08C9, 0x024E, 0x1382, 0x0951, 0x00A5, 0x0A2A, 0x0059, + 0x0A9E, 0x0B42, 0x004E, 0x0942, 0x03ED, 0x09B2, 0x02D2, 0x0849, + 0x0035, 0x0216, 0x0961, 0x0BAF, 0x00AE, 0x0826, 0x0287, 0x0A1A, + 0x0393, 0x0221, 0x09A2, 0x086D, 0x0226, 0x0871, 0x0039, 0x082A, + 0x08C2, 0x08E1, 0x0845, 0x0207, 0x0B23, 0x0015, 0x00D1, 0x0B83, + 0x037F, 0x0252, 0x08A9, 0x0099, 0x0A13, 0x0053, 0x0807, 0x03CD, + 0x0BDE, 0x0016, 0x089A, 0x0232, 0x035F, 0x0A8E, 0x0AC3, 0x022F, + 0x0263, 0x0829, 0x004D, 0x0132, 0x0806, 0x0311, 0x01B1, 0x0941, + 0x0086, 0x000B, 0x1122, 0x0025, 0x0842, 0x00BD, 0x0BCF, 0x03A2, + 0x0043, 0x0B03, 0x0895, 0x0A8F, 0x008A, 0x09EF, 0x0253, 0x0A1B, + 0x0182, 0x0243, 0x0A92, 0x00CD, 0x083E, 0x030B, 0x0223, 0x081A, + 0x0A9F, 0x0193, 0x00BE, 0x0017, 0x0931, 0x0391, 0x037E, 0x09C1, + 0x0312, 0x0333, 0x03B2, 0x083D, 0x08B1, 0x00B2, 0x002E, 0x021D, + 0x0A9D, 0x0192, 0x02AE, 0x0102, 0x0022, 0x081B, 0x0222, 0x009E, + 0x021E, 0x000A, 0x089F, 0x0217, 0x0BCE, 0x0052, 0x020F, 0x0A97, + 0x0282, 0x008E, 0x0A3F, 0x01FD, 0x00A3, 0x0019, 0x08A2, 0x0301, + 0x036E, 0x01FE, 0x03BE, 0x0ABE, 0x01CE, 0x0302, 0x029B, 0x0051, + 0x0883, 0x008F, 0x0BAE, 0x01DF, 0x0183, 0x0912, 0x000E, 0x020D, + 0x01EE, 0x0B4F, 0x0033, 0x0103, 0x020E, 0x0832, 0x01AF, 0x0913, + 0x01DE, 0x0203, 0x001E, 0x0092, 0x0093, 0x000F, 0x015F, 0x0291, + 0x0281, 0x0813, 0x001F, 0x01CF, 0x033F, 0x0023, 0x01BF, 0x0202, + 0x016F, 0x017E, 0x03AD, 0x0201, 0x034E, 0x0BBD, 0x036D, 0x017F, + 0x0211, 0x038E, 0x0212, 0x032E, 0x034D, 0x035E, 0x037D, 0x039E, + 0x032F, 0x033E, 0x035D, 0x038F, 0x039F +}; + +static const uint16_t percentile_arr_10x10_1[234] { + 0x07CD, 0x6E21, 0x24F1, 0x8443, 0xD7AE, 0x24C2, 0x1C62, 0xCCA3, + 0x1C33, 0xFDEF, 0x2532, 0x55DF, 0x1472, 0x6C3E, 0x14D2, 0x34DD, + 0x1452, 0x745D, 0x4D51, 0x8DD1, 0x247D, 0x75FF, 0x0CB3, 0x17BE, + 0x6CAE, 0x17DD, 0x1571, 0x3D06, 0x4E31, 0x0DA2, 0x67BD, 0x160D, + 0x2C4E, 0x0D22, 0x176E, 0x3CB2, 0x142E, 0x4DFE, 0x0F4F, 0x1435, + 0x0F01, 0x0D42, 0x0F7D, 0x0CB5, 0x1E03, 0x149F, 0x1C96, 0x141F, + 0x14B9, 0x0FAF, 0x0439, 0x0E91, 0x2682, 0x1D13, 0x1FAD, 0x0407, + 0x3471, 0x0C86, 0x0F6D, 0x0D15, 0x0D61, 0x040B, 0x0C6D, 0x0C16, + 0x0C9A, 0x0D0A, 0x0593, 0x0CD1, 0x248F, 0x0C2F, 0x3C42, 0x1523, + 0x0445, 0x0E81, 0x0CA2, 0x1525, 0x0406, 0x1C8A, 0x0C1A, 0x04BD, + 0x0F5E, 0x0F3F, 0x1F4E, 0x0E1D, 0x0423, 0x0DCF, 0x044D, 0x0D92, + 0x0583, 0x0DB1, 0x1449, 0x15EE, 0x0F5F, 0x079F, 0x0D19, 0x0409, + 0x04CD, 0x05FD, 0x143D, 0x0612, 0x0D03, 0x0D82, 0x04B1, 0x0C95, + 0x0C2A, 0x049E, 0x05AF, 0x0D31, 0x05BE, 0x04E1, 0x0D05, 0x0516, + 0x0711, 0x05C1, 0x0509, 0x0D41, 0x0493, 0x048E, 0x0602, 0x05BF, + 0x0CA5, 0x0529, 0x0535, 0x0D12, 0x0539, 0x0451, 0x0C29, 0x071F, + 0x040A, 0x0F3D, 0x0432, 0x059F, 0x0425, 0x0C99, 0x05DE, 0x05CE, + 0x0C0F, 0x0489, 0x051A, 0x0501, 0x0415, 0x057F, 0x0431, 0x0E13, + 0x040D, 0x041D, 0x075D, 0x0C53, 0x0502, 0x04C1, 0x049D, 0x0426, + 0x040E, 0x05A1, 0x055F, 0x0781, 0x0591, 0x04A9, 0x048B, 0x0D8E, + 0x052E, 0x0412, 0x0521, 0x0405, 0x04AD, 0x074D, 0x0611, 0x077E, + 0x078F, 0x078D, 0x048D, 0x041E, 0x0487, 0x0461, 0x0C85, 0x05ED, + 0x0402, 0x0483, 0x0419, 0x0511, 0x0491, 0x0482, 0x059E, 0x068D, + 0x055D, 0x072E, 0x05DD, 0x054E, 0x0441, 0x0422, 0x052F, 0x057D, + 0x072D, 0x079D, 0x0CA1, 0x072F, 0x079E, 0x0581, 0x042D, 0x055E, + 0x0601, 0x0413, 0x0692, 0x0403, 0x051F, 0x053F, 0x054F, 0x05CD, + 0x070F, 0x071D, 0x05AE, 0x05BD, 0x0492, 0x056E, 0x0411, 0x0417, + 0x041B, 0x0421, 0x053E, 0x056F, 0x057E, 0x058F, 0x060E, 0x0622, + 0x0683, 0x0702, 0x070D, 0x070E, 0x071E, 0x073E, 0x076F, 0x078E, + 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_10x10 { + 10, 10, + { 453, 234 }, + { 1095, 472 }, + { 0, 70 }, + { percentile_arr_10x10_0, percentile_arr_10x10_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 10) +static const uint16_t percentile_arr_12x10_0[491] { + 0x0334, 0x9954, 0x8514, 0x7128, 0x6364, 0xC174, 0x5D34, 0x5866, + 0x5975, 0x5354, 0xAF14, 0x506A, 0x5108, 0x5724, 0x5308, 0x4544, + 0x4918, 0x4064, 0x49E2, 0x4179, 0x8163, 0x4054, 0xF81C, 0x394A, + 0x38F3, 0x4172, 0x38F5, 0xA06F, 0x68EA, 0x69F2, 0x3134, 0x31A4, + 0x305A, 0x68DA, 0x3056, 0x3146, 0x31F5, 0x3148, 0x5A61, 0x32C1, + 0x31D2, 0x307E, 0x29E3, 0x30E6, 0x59C3, 0x2984, 0x29B6, 0x28F9, + 0x5204, 0x28EE, 0x50CA, 0x2997, 0x48C6, 0x4838, 0x2953, 0x200C, + 0x2943, 0x2173, 0x2D08, 0x4162, 0x29B4, 0x2314, 0x21B3, 0x212B, + 0x210C, 0x48E3, 0x60DE, 0x205F, 0x20FE, 0x2028, 0x21A6, 0x404F, + 0x20D6, 0x2214, 0x2127, 0x1873, 0x40CF, 0x206E, 0x1B09, 0x21C6, + 0x2075, 0x19D5, 0x2305, 0x18D3, 0x2076, 0x1804, 0x230A, 0x304B, + 0x20BB, 0x18B6, 0x1936, 0x1B19, 0x3037, 0x187F, 0x18A7, 0x1B85, + 0x30BA, 0x183B, 0x1027, 0x18EF, 0x1B21, 0x1879, 0x10AB, 0x1917, + 0x1114, 0x18BF, 0x1074, 0x1994, 0x2847, 0x111B, 0x28F2, 0x11E5, + 0x19A7, 0x113A, 0x1046, 0x28B7, 0x207A, 0x182B, 0x1155, 0x104A, + 0x1344, 0x293B, 0x11D3, 0x2014, 0x1044, 0x1018, 0x13A1, 0x1315, + 0x2524, 0x20DF, 0x10E5, 0x1126, 0x12A2, 0x1824, 0x2271, 0x11F1, + 0x2964, 0x12D1, 0x115A, 0x092A, 0x2341, 0x1A2D, 0x12E1, 0x090A, + 0x13BF, 0x0A4D, 0x2119, 0x0BC1, 0x1233, 0x1A8A, 0x2008, 0x1159, + 0x1A89, 0x08D5, 0x1156, 0x0834, 0x13EE, 0x1169, 0x1187, 0x1AA3, + 0x1229, 0x1331, 0x0A85, 0x0937, 0x1704, 0x08FD, 0x2124, 0x0B13, + 0x1251, 0x0AAD, 0x082C, 0x091A, 0x18D9, 0x0A99, 0x1848, 0x18E9, + 0x0B95, 0x1144, 0x0AF1, 0x1A25, 0x131A, 0x09C5, 0x0986, 0x1BDF, + 0x0B24, 0x0965, 0x1262, 0x0949, 0x0872, 0x09C2, 0x12C2, 0x0916, + 0x085E, 0x0B06, 0x08CB, 0x08C7, 0x1242, 0x1BEF, 0x0A9A, 0x1152, + 0x08B3, 0x0AA9, 0x090B, 0x08D2, 0x1B22, 0x0B04, 0x0865, 0x0A15, + 0x1286, 0x0A83, 0x0A95, 0x09D1, 0x0A06, 0x0196, 0x1139, 0x0A3D, + 0x0933, 0x13B1, 0x0123, 0x0D04, 0x08E2, 0x122E, 0x08A6, 0x00CE, + 0x0A31, 0x1241, 0x0B51, 0x1057, 0x1171, 0x007D, 0x1145, 0x0A0A, + 0x0129, 0x09FF, 0x089B, 0x085B, 0x0063, 0x0AB1, 0x0A1F, 0x0A5D, + 0x0AA5, 0x0036, 0x0904, 0x0B86, 0x0A8B, 0x0897, 0x11E1, 0x0332, + 0x083F, 0x0A19, 0x02B3, 0x0859, 0x08C3, 0x0855, 0x11B5, 0x01A5, + 0x0AB2, 0x0392, 0x10DD, 0x09A3, 0x00ED, 0x0907, 0x1161, 0x002F, + 0x0887, 0x0216, 0x0ABD, 0x0B81, 0x0A93, 0x0A21, 0x003A, 0x0ACD, + 0x0AA1, 0x0A35, 0x0272, 0x0BDD, 0x03FE, 0x0BAF, 0x0869, 0x0213, + 0x088B, 0x020B, 0x00B5, 0x1035, 0x08F1, 0x0151, 0x0A4E, 0x0239, + 0x0BA2, 0x00AA, 0x0896, 0x0382, 0x0A08, 0x0A05, 0x0A09, 0x0142, + 0x086D, 0x004E, 0x0B23, 0x0106, 0x0807, 0x036F, 0x0995, 0x03FD, + 0x08AF, 0x08C5, 0x0062, 0x0053, 0x0B42, 0x0826, 0x021A, 0x01A2, + 0x09B1, 0x00C9, 0x09B2, 0x0045, 0x0207, 0x08B9, 0x00A5, 0x0AD2, + 0x0095, 0x003E, 0x0A32, 0x0383, 0x0849, 0x0135, 0x029E, 0x0A26, + 0x023E, 0x0BFF, 0x0A52, 0x0311, 0x001B, 0x0915, 0x0A8D, 0x0223, + 0x022A, 0x0BED, 0x0086, 0x0A96, 0x0222, 0x035F, 0x0A43, 0x085D, + 0x0303, 0x0393, 0x0A63, 0x082A, 0x037F, 0x0932, 0x0043, 0x0292, + 0x03CD, 0x0BDE, 0x009F, 0x0125, 0x08A9, 0x0253, 0x0015, 0x0192, + 0x0A17, 0x08C2, 0x0316, 0x00D1, 0x0282, 0x0871, 0x0312, 0x0122, + 0x0A9F, 0x02AE, 0x0006, 0x0A8E, 0x08E1, 0x0016, 0x0B0B, 0x00AE, + 0x0025, 0x0193, 0x0AC3, 0x0017, 0x0307, 0x00BD, 0x08BE, 0x0039, + 0x0BB2, 0x021B, 0x01FD, 0x084D, 0x03CE, 0x00A3, 0x0302, 0x0BCF, + 0x0033, 0x0391, 0x028F, 0x0852, 0x0287, 0x008A, 0x0333, 0x080B, + 0x0131, 0x01C1, 0x037E, 0x0A0F, 0x00B1, 0x002E, 0x0099, 0x0902, + 0x009A, 0x003D, 0x0982, 0x0301, 0x00CD, 0x0941, 0x0042, 0x0183, + 0x029D, 0x08A2, 0x021D, 0x001A, 0x0A97, 0x01EF, 0x01CE, 0x0051, + 0x0BAE, 0x022F, 0x03BE, 0x021E, 0x000A, 0x09DF, 0x0029, 0x020D, + 0x02BE, 0x029B, 0x09EE, 0x00B2, 0x0912, 0x036E, 0x009E, 0x0022, + 0x0019, 0x0892, 0x0032, 0x01FE, 0x0083, 0x023F, 0x0B96, 0x000E, + 0x008F, 0x0113, 0x0103, 0x001E, 0x0A0E, 0x0013, 0x008E, 0x0281, + 0x09AF, 0x017E, 0x0203, 0x016F, 0x0291, 0x0023, 0x0093, 0x03BD, + 0x001F, 0x01CF, 0x01DE, 0x0201, 0x01BF, 0x0B4F, 0x000F, 0x0202, + 0x037D, 0x038E, 0x0211, 0x0212, 0x034E, 0x039F, 0x03AD, 0x015F, + 0x017F, 0x032E, 0x033F, 0x034D, 0x035E, 0x036D, 0x032F, 0x033E, + 0x035D, 0x038F, 0x039E +}; + +static const uint16_t percentile_arr_12x10_1[240] { + 0x0621, 0xA443, 0xFCC2, 0x3CA3, 0x1D32, 0x14F1, 0x7462, 0x1433, + 0x27CD, 0x2571, 0x57AE, 0x5DD1, 0x64B3, 0x44D2, 0x2C72, 0x25A2, + 0x1E31, 0x55DF, 0x4C52, 0x1DEF, 0x0D51, 0x3C5D, 0x3C3E, 0x74DD, + 0x347D, 0x27BE, 0x5CB5, 0x17DD, 0x2C14, 0x0CAE, 0x24B2, 0x15FF, + 0x2701, 0x0D42, 0x1FBD, 0x0C35, 0x1603, 0x060D, 0x1D93, 0x0C96, + 0x1C07, 0x1522, 0x0D06, 0x0F4F, 0x0C9F, 0x1F6E, 0x0D86, 0x0C2E, + 0x1DFE, 0x0682, 0x1E91, 0x0F7D, 0x0C86, 0x040B, 0x1513, 0x044E, + 0x14D1, 0x0C39, 0x14B9, 0x1C71, 0x05B1, 0x0C1F, 0x0681, 0x1445, + 0x0C16, 0x0D95, 0x1583, 0x0D61, 0x0FAD, 0x1442, 0x048F, 0x0D0A, + 0x049A, 0x0F6D, 0x146D, 0x0C2F, 0x0D25, 0x0406, 0x0C1A, 0x0D23, + 0x0612, 0x0FAF, 0x0F11, 0x0592, 0x0515, 0x14E1, 0x0602, 0x048A, + 0x0E1D, 0x0CBD, 0x0F9F, 0x0423, 0x075E, 0x174E, 0x0426, 0x0404, + 0x0C22, 0x0CA2, 0x0DEE, 0x0CA5, 0x0F3F, 0x05C1, 0x0CCD, 0x0503, + 0x044D, 0x0D16, 0x0449, 0x0D82, 0x0613, 0x0585, 0x0519, 0x0C95, + 0x075F, 0x0D35, 0x04B1, 0x0509, 0x0531, 0x0DA1, 0x049E, 0x040A, + 0x05CF, 0x0D41, 0x0415, 0x0692, 0x05FD, 0x0C25, 0x04A1, 0x0529, + 0x0591, 0x0C93, 0x057F, 0x04C1, 0x0512, 0x051A, 0x078D, 0x0451, + 0x0C0F, 0x0487, 0x0611, 0x0432, 0x042A, 0x05AF, 0x0461, 0x072D, + 0x0409, 0x0405, 0x0D39, 0x05DE, 0x048E, 0x0499, 0x0483, 0x04A9, + 0x0491, 0x042D, 0x049D, 0x0429, 0x040E, 0x05AE, 0x0521, 0x043D, + 0x0581, 0x05DD, 0x0492, 0x0CAD, 0x041E, 0x058F, 0x071F, 0x072F, + 0x0419, 0x073D, 0x057D, 0x0511, 0x05CE, 0x041D, 0x0485, 0x056E, + 0x0412, 0x0431, 0x05BF, 0x0441, 0x054E, 0x0489, 0x0421, 0x0502, + 0x0408, 0x040D, 0x051F, 0x059F, 0x073E, 0x078F, 0x0482, 0x079D, + 0x0C02, 0x05BE, 0x048B, 0x0411, 0x0505, 0x057E, 0x052E, 0x074D, + 0x077E, 0x054F, 0x0601, 0x055F, 0x068D, 0x070D, 0x070F, 0x071E, + 0x072E, 0x05CD, 0x0403, 0x0501, 0x055D, 0x059E, 0x0781, 0x0413, + 0x0417, 0x041B, 0x0453, 0x048D, 0x052F, 0x053E, 0x053F, 0x055E, + 0x056F, 0x058E, 0x05BD, 0x05ED, 0x060E, 0x0622, 0x0683, 0x0702, + 0x070E, 0x071D, 0x075D, 0x076F, 0x078E, 0x079E, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_12x10 = +{ + 12, 10, + { 491, 240 }, + { 1099, 341 }, + { 0, 23 }, + { percentile_arr_12x10_0, percentile_arr_12x10_1 } +}; +#endif + +#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 12) +static const uint16_t percentile_arr_12x12_0[529] { + 0x0334, 0xF534, 0x8514, 0x8954, 0x7F14, 0xFB54, 0x7B08, 0x7128, + 0x7974, 0x6179, 0x6B64, 0x6908, 0x606A, 0x6724, 0xB544, 0xB066, + 0xA14A, 0x5118, 0x9975, 0x51F9, 0x981C, 0x49CA, 0x4854, 0x886F, + 0x88D4, 0x48EE, 0x41E2, 0x4163, 0x40F3, 0x4261, 0x4064, 0x407E, + 0x385A, 0x42C1, 0x4172, 0x38EA, 0x3946, 0x78CF, 0xA056, 0x38DE, + 0x3D08, 0x38F9, 0x3B14, 0x38FE, 0xA134, 0x38B8, 0x31A4, 0x71D2, + 0x60DA, 0x39C3, 0x99BA, 0x60CA, 0x39F2, 0x30F5, 0x304F, 0x31B6, + 0x31F5, 0x3204, 0x3148, 0x305F, 0x2953, 0x3194, 0x3184, 0x310C, + 0x889C, 0x300C, 0x2943, 0x30EF, 0x28C6, 0x2997, 0x2838, 0x58E6, + 0x20E4, 0x28E3, 0x2873, 0x29E3, 0x2A84, 0x28D3, 0x492B, 0x2962, + 0x286E, 0x20BF, 0x21AA, 0x29A6, 0x6A14, 0x2828, 0x89C6, 0x21B3, + 0x2305, 0x29B4, 0x2173, 0x2127, 0x20D6, 0x407F, 0x2294, 0x21D9, + 0x21D5, 0x2004, 0x404B, 0x18DF, 0x2079, 0x219B, 0x18A8, 0x2385, + 0x1936, 0x21AB, 0x188C, 0x1B09, 0x18BA, 0x203B, 0x187A, 0x1875, + 0x2344, 0x18BB, 0x18B6, 0x193A, 0x1837, 0x1914, 0x1846, 0x1876, + 0x1884, 0x1D24, 0x182B, 0x284A, 0x18A7, 0x18AB, 0x1917, 0x322D, + 0x1047, 0x1874, 0x1818, 0x18F2, 0x1164, 0x1B89, 0x2959, 0x1B21, + 0x39E5, 0x1827, 0x10F4, 0x18B7, 0x11D3, 0x1A4D, 0x1315, 0x12AD, + 0x1AD1, 0x3A71, 0x1319, 0x11A7, 0x2044, 0x2F04, 0x2341, 0x10E5, + 0x1155, 0x195A, 0x1024, 0x111B, 0x1251, 0x1233, 0x12E1, 0x13A1, + 0x13BF, 0x212A, 0x22A2, 0x113B, 0x23DF, 0x10D5, 0x2399, 0x0814, + 0x1126, 0x13EE, 0x1285, 0x10C4, 0x18FD, 0x20D9, 0x0987, 0x1242, + 0x29C5, 0x2313, 0x0898, 0x13C1, 0x08C8, 0x11F1, 0x1034, 0x1B24, + 0x0B0A, 0x11E9, 0x0808, 0x125D, 0x18E9, 0x0848, 0x1395, 0x0965, + 0x123D, 0x2186, 0x1295, 0x18CE, 0x098B, 0x0BEF, 0x1504, 0x082C, + 0x0A41, 0x1144, 0x0A89, 0x0956, 0x1331, 0x085E, 0x0B04, 0x128A, + 0x12A3, 0x1937, 0x19C2, 0x0952, 0x0872, 0x08B4, 0x1262, 0x1124, + 0x1969, 0x1063, 0x0AF1, 0x1225, 0x0894, 0x11C9, 0x18D2, 0x0ACD, + 0x0A29, 0x0B06, 0x09B5, 0x18C7, 0x0916, 0x1088, 0x09FF, 0x2206, + 0x0A15, 0x08B3, 0x0B51, 0x0A1F, 0x18CB, 0x0AC2, 0x0A2E, 0x1865, + 0x08AC, 0x0A31, 0x08A4, 0x138A, 0x0A99, 0x09D1, 0x0A86, 0x189B, + 0x0283, 0x0BDD, 0x0ABD, 0x1933, 0x083F, 0x1386, 0x0923, 0x0322, + 0x0869, 0x10DD, 0x13B1, 0x082F, 0x087D, 0x11B9, 0x085B, 0x08ED, + 0x00C3, 0x08E2, 0x084E, 0x0887, 0x0855, 0x0A0A, 0x0857, 0x0B92, + 0x1036, 0x12A5, 0x0293, 0x0945, 0x08A6, 0x0196, 0x19A3, 0x036F, + 0x0904, 0x1205, 0x09E1, 0x0381, 0x0971, 0x1219, 0x0BAF, 0x0949, + 0x00AF, 0x0AA9, 0x018A, 0x0907, 0x0BFD, 0x003A, 0x0BCD, 0x0AB2, + 0x088B, 0x0252, 0x0A4E, 0x03FF, 0x0845, 0x0897, 0x0059, 0x090B, + 0x0B42, 0x0807, 0x0A16, 0x0853, 0x0A8D, 0x01B2, 0x0AB1, 0x091A, + 0x0195, 0x0A35, 0x00B5, 0x10AA, 0x0115, 0x0A21, 0x0096, 0x0A08, + 0x03FE, 0x0B7F, 0x08B9, 0x12B3, 0x023E, 0x0A23, 0x029E, 0x08F1, + 0x01A9, 0x0BDE, 0x0843, 0x02D2, 0x0A1A, 0x08C5, 0x0151, 0x0A43, + 0x0332, 0x0383, 0x0826, 0x0BED, 0x10C2, 0x00AE, 0x0B82, 0x0213, + 0x0232, 0x085D, 0x02A1, 0x101B, 0x035F, 0x0303, 0x0A39, 0x0207, + 0x0A53, 0x0142, 0x01A5, 0x082A, 0x0099, 0x0A17, 0x03CF, 0x0906, + 0x0125, 0x0A96, 0x0A9A, 0x0209, 0x0393, 0x0961, 0x0131, 0x0A88, + 0x0139, 0x099A, 0x0292, 0x0272, 0x0862, 0x08BE, 0x0141, 0x02C3, + 0x0886, 0x0039, 0x08A9, 0x01A2, 0x01B1, 0x0851, 0x020B, 0x086D, + 0x0312, 0x08CD, 0x020F, 0x0311, 0x0BCE, 0x0135, 0x0006, 0x0849, + 0x0132, 0x0A8F, 0x022F, 0x022A, 0x0AAE, 0x0A8E, 0x0263, 0x03A2, + 0x083E, 0x009A, 0x021B, 0x0835, 0x0323, 0x0871, 0x0993, 0x0226, + 0x0302, 0x0922, 0x0119, 0x0222, 0x021D, 0x0B07, 0x08C9, 0x037E, + 0x08BD, 0x0042, 0x00D1, 0x0B33, 0x01C1, 0x0B9A, 0x0282, 0x088A, + 0x0182, 0x083D, 0x004D, 0x010A, 0x0A1E, 0x0019, 0x00B2, 0x0999, + 0x00A5, 0x0095, 0x0817, 0x0022, 0x031A, 0x0902, 0x00A3, 0x01BF, + 0x029F, 0x0816, 0x03B2, 0x0015, 0x0391, 0x0BBE, 0x01FE, 0x1129, + 0x002E, 0x01DF, 0x0301, 0x0033, 0x0B6E, 0x00E1, 0x0297, 0x00B1, + 0x009F, 0x0B16, 0x000A, 0x001A, 0x0052, 0x080B, 0x030B, 0x029D, + 0x0BAE, 0x01FD, 0x020E, 0x00A2, 0x0A3F, 0x0192, 0x0ABE, 0x020D, + 0x008F, 0x028B, 0x0083, 0x0025, 0x09EE, 0x01EF, 0x0029, 0x0291, + 0x0B4F, 0x0396, 0x0287, 0x008E, 0x0092, 0x0B4E, 0x017E, 0x001E, + 0x009E, 0x0103, 0x080F, 0x000E, 0x0113, 0x0203, 0x01CF, 0x0183, + 0x01CE, 0x001F, 0x0112, 0x01DE, 0x038E, 0x0832, 0x033E, 0x0212, + 0x029B, 0x0023, 0x016F, 0x0201, 0x09AF, 0x0202, 0x0281, 0x035E, + 0x034D, 0x037D, 0x03AD, 0x0013, 0x0093, 0x015F, 0x0211, 0x033F, + 0x036D, 0x039F, 0x03BD, 0x017F, 0x032E, 0x032F, 0x035D, 0x038F, + 0x039E +}; + +static const uint16_t percentile_arr_12x12_1[246] { + 0x0443, 0xFFCD, 0x2C62, 0x2E21, 0x3CF1, 0x34C2, 0x4CDD, 0x2452, + 0xD5DF, 0x1DD1, 0x0FAE, 0x64A3, 0x0C7D, 0x3433, 0x1CD2, 0x2DEF, + 0x0C3E, 0x1D71, 0xA472, 0x0D32, 0x54B3, 0x4D51, 0x445D, 0x0E31, + 0x1FDD, 0x0DFF, 0x0CAE, 0x45A2, 0x2FBE, 0xA4B9, 0x1C4E, 0x2C9F, + 0x160D, 0x0D42, 0x342E, 0x074F, 0x1414, 0x0F6E, 0x0CB2, 0x34B5, + 0x0DFE, 0x0D86, 0x1496, 0x1D22, 0x0691, 0x140B, 0x041F, 0x0C35, + 0x1D93, 0x1506, 0x1439, 0x0C9A, 0x0F01, 0x2442, 0x0C8F, 0x04D1, + 0x1486, 0x0C6D, 0x0513, 0x0C71, 0x0E82, 0x177D, 0x0E03, 0x07BD, + 0x0C2F, 0x0D83, 0x07AF, 0x0D61, 0x1407, 0x0DB1, 0x050A, 0x0C94, + 0x07AD, 0x0D8A, 0x0C04, 0x0416, 0x0C49, 0x0445, 0x15C1, 0x0C1A, + 0x0525, 0x0595, 0x0C8A, 0x075E, 0x0CBD, 0x0681, 0x0F4E, 0x075F, + 0x061D, 0x1541, 0x0CB1, 0x0F3F, 0x0406, 0x076D, 0x0DCF, 0x05EE, + 0x0D23, 0x0599, 0x0CCD, 0x0711, 0x0C23, 0x079F, 0x0D15, 0x0585, + 0x04A2, 0x042A, 0x0D31, 0x05BF, 0x0D92, 0x0C26, 0x043D, 0x0C93, + 0x0502, 0x0C15, 0x048B, 0x0D03, 0x0613, 0x0516, 0x0495, 0x0C29, + 0x04A5, 0x040F, 0x0425, 0x0539, 0x0D19, 0x04E1, 0x05BE, 0x0422, + 0x0432, 0x0C0A, 0x0431, 0x041E, 0x0492, 0x04A9, 0x0582, 0x0529, + 0x0487, 0x0C4D, 0x0512, 0x049E, 0x0505, 0x0451, 0x0D7F, 0x0489, + 0x0602, 0x05DE, 0x0591, 0x0535, 0x074D, 0x055E, 0x04C1, 0x0612, + 0x05DD, 0x05FD, 0x0C61, 0x0521, 0x0484, 0x05CE, 0x0581, 0x0491, + 0x051A, 0x04A1, 0x048E, 0x040D, 0x0499, 0x071F, 0x072E, 0x075D, + 0x0441, 0x0589, 0x057E, 0x0CAD, 0x0501, 0x054F, 0x0692, 0x0511, + 0x049D, 0x0509, 0x056E, 0x040E, 0x0409, 0x0601, 0x048D, 0x0413, + 0x053E, 0x0419, 0x072D, 0x0408, 0x0485, 0x042D, 0x041D, 0x05A1, + 0x0781, 0x0402, 0x05ED, 0x0C82, 0x0403, 0x057D, 0x05CD, 0x0611, + 0x0488, 0x0411, 0x054E, 0x051F, 0x053F, 0x056F, 0x059F, 0x070F, + 0x071D, 0x073D, 0x073E, 0x077E, 0x078F, 0x0405, 0x079D, 0x079E, + 0x058E, 0x0412, 0x055D, 0x05AE, 0x041B, 0x0421, 0x0453, 0x0417, + 0x0483, 0x052E, 0x052F, 0x055F, 0x058F, 0x059E, 0x05AF, 0x05BD, + 0x060E, 0x0622, 0x0683, 0x068D, 0x0702, 0x070D, 0x070E, 0x071E, + 0x072F, 0x076F, 0x078D, 0x078E, 0x07BF, 0x07CE +}; + +static const packed_percentile_table block_pcd_12x12 { + 12, 12, + { 529, 246 }, + { 1435, 335 }, + { 0, 22 }, + { percentile_arr_12x12_0, percentile_arr_12x12_1 } +}; +#endif + +/** + * @brief Fetch the packed percentile table for the given 2D block size. + * + * @param xdim The block x size. + * @param ydim The block y size. + * + * @return The packed table. + */ +static const packed_percentile_table *get_packed_table( + int xdim, + int ydim +) { + int idx = (ydim << 8) | xdim; + switch (idx) + { +#if ASTCENC_BLOCK_MAX_TEXELS >= (4 * 4) + case 0x0404: return &block_pcd_4x4; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 4) + case 0x0405: return &block_pcd_5x4; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 5) + case 0x0505: return &block_pcd_5x5; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 5) + case 0x0506: return &block_pcd_6x5; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 6) + case 0x0606: return &block_pcd_6x6; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 5) + case 0x0508: return &block_pcd_8x5; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 6) + case 0x0608: return &block_pcd_8x6; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 8) + case 0x0808: return &block_pcd_8x8; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 5) + case 0x050A: return &block_pcd_10x5; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 6) + case 0x060A: return &block_pcd_10x6; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 8) + case 0x080A: return &block_pcd_10x8; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 10) + case 0x0A0A: return &block_pcd_10x10; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 10) + case 0x0A0C: return &block_pcd_12x10; +#endif +#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 12) + case 0x0C0C: return &block_pcd_12x12; +#endif + } + + // Should never hit this with a valid 2D block size + return nullptr; +} + +/* See header for documentation. */ +const float *get_2d_percentile_table( + unsigned int xdim, + unsigned int ydim +) { + float* unpacked_table = new float[WEIGHTS_MAX_BLOCK_MODES]; + const packed_percentile_table *apt = get_packed_table(xdim, ydim); + + // Set the default percentile + for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++) + { + unpacked_table[i] = 1.0f; + } + + // Populate the unpacked percentile values + for (int i = 0; i < 2; i++) + { + unsigned int itemcount = apt->item_count[i]; + unsigned int difscale = apt->difscales[i]; + unsigned int accum = apt->initial_percs[i]; + const uint16_t *item_ptr = apt->items[i]; + + for (unsigned int j = 0; j < itemcount; j++) + { + uint16_t item = item_ptr[j]; + unsigned int idx = item & 0x7FF; + unsigned int weight = (item >> 11) & 0x1F; + accum += weight; + unpacked_table[idx] = static_cast<float>(accum) / static_cast<float>(difscale); + } + } + + return unpacked_table; +} +#endif + +/* See header for documentation. */ +bool is_legal_2d_block_size( + unsigned int xdim, + unsigned int ydim +) { + unsigned int idx = (xdim << 8) | ydim; + switch (idx) + { + case 0x0404: + case 0x0504: + case 0x0505: + case 0x0605: + case 0x0606: + case 0x0805: + case 0x0806: + case 0x0808: + case 0x0A05: + case 0x0A06: + case 0x0A08: + case 0x0A0A: + case 0x0C0A: + case 0x0C0C: + return true; + } + + return false; +} + +/* See header for documentation. */ +bool is_legal_3d_block_size( + unsigned int xdim, + unsigned int ydim, + unsigned int zdim +) { + unsigned int idx = (xdim << 16) | (ydim << 8) | zdim; + switch (idx) + { + case 0x030303: + case 0x040303: + case 0x040403: + case 0x040404: + case 0x050404: + case 0x050504: + case 0x050505: + case 0x060505: + case 0x060605: + case 0x060606: + return true; + } + + return false; +} diff --git a/thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp b/thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp new file mode 100644 index 0000000000..f25140d4c7 --- /dev/null +++ b/thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp @@ -0,0 +1,1350 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions for finding best endpoint format. + * + * We assume there are two independent sources of error in any given partition: + * + * - Encoding choice errors + * - Quantization errors + * + * Encoding choice errors are caused by encoder decisions. For example: + * + * - Using luminance instead of separate RGB components. + * - Using a constant 1.0 alpha instead of storing an alpha component. + * - Using RGB+scale instead of storing two full RGB endpoints. + * + * Quantization errors occur due to the limited precision we use for storage. These errors generally + * scale with quantization level, but are not actually independent of color encoding. In particular: + * + * - If we can use offset encoding then quantization error is halved. + * - If we can use blue-contraction then quantization error for RG is halved. + * - If we use HDR endpoints the quantization error is higher. + * + * Apart from these effects, we assume the error is proportional to the quantization step size. + */ + + +#include "astcenc_internal.h" +#include "astcenc_vecmathlib.h" + +#include <assert.h> + +/** + * @brief Compute the errors of the endpoint line options for one partition. + * + * Uncorrelated data assumes storing completely independent RGBA channels for each endpoint. Same + * chroma data assumes storing RGBA endpoints which pass though the origin (LDR only). RGBL data + * assumes storing RGB + lumashift (HDR only). Luminance error assumes storing RGB channels as a + * single value. + * + * + * @param pi The partition info data. + * @param partition_index The partition index to compule the error for. + * @param blk The image block. + * @param uncor_pline The endpoint line assuming uncorrelated endpoints. + * @param[out] uncor_err The computed error for the uncorrelated endpoint line. + * @param samec_pline The endpoint line assuming the same chroma for both endpoints. + * @param[out] samec_err The computed error for the uncorrelated endpoint line. + * @param rgbl_pline The endpoint line assuming RGB + lumashift data. + * @param[out] rgbl_err The computed error for the RGB + lumashift endpoint line. + * @param l_pline The endpoint line assuming luminance data. + * @param[out] l_err The computed error for the luminance endpoint line. + * @param[out] a_drop_err The computed error for dropping the alpha component. + */ +static void compute_error_squared_rgb_single_partition( + const partition_info& pi, + int partition_index, + const image_block& blk, + const processed_line3& uncor_pline, + float& uncor_err, + const processed_line3& samec_pline, + float& samec_err, + const processed_line3& rgbl_pline, + float& rgbl_err, + const processed_line3& l_pline, + float& l_err, + float& a_drop_err +) { + vfloat4 ews = blk.channel_weight; + + unsigned int texel_count = pi.partition_texel_count[partition_index]; + const uint8_t* texel_indexes = pi.texels_of_partition[partition_index]; + promise(texel_count > 0); + + vfloatacc a_drop_errv = vfloatacc::zero(); + vfloat default_a(blk.get_default_alpha()); + + vfloatacc uncor_errv = vfloatacc::zero(); + vfloat uncor_bs0(uncor_pline.bs.lane<0>()); + vfloat uncor_bs1(uncor_pline.bs.lane<1>()); + vfloat uncor_bs2(uncor_pline.bs.lane<2>()); + + vfloat uncor_amod0(uncor_pline.amod.lane<0>()); + vfloat uncor_amod1(uncor_pline.amod.lane<1>()); + vfloat uncor_amod2(uncor_pline.amod.lane<2>()); + + vfloatacc samec_errv = vfloatacc::zero(); + vfloat samec_bs0(samec_pline.bs.lane<0>()); + vfloat samec_bs1(samec_pline.bs.lane<1>()); + vfloat samec_bs2(samec_pline.bs.lane<2>()); + + vfloatacc rgbl_errv = vfloatacc::zero(); + vfloat rgbl_bs0(rgbl_pline.bs.lane<0>()); + vfloat rgbl_bs1(rgbl_pline.bs.lane<1>()); + vfloat rgbl_bs2(rgbl_pline.bs.lane<2>()); + + vfloat rgbl_amod0(rgbl_pline.amod.lane<0>()); + vfloat rgbl_amod1(rgbl_pline.amod.lane<1>()); + vfloat rgbl_amod2(rgbl_pline.amod.lane<2>()); + + vfloatacc l_errv = vfloatacc::zero(); + vfloat l_bs0(l_pline.bs.lane<0>()); + vfloat l_bs1(l_pline.bs.lane<1>()); + vfloat l_bs2(l_pline.bs.lane<2>()); + + vint lane_ids = vint::lane_id(); + for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH) + { + vint tix(texel_indexes + i); + + vmask mask = lane_ids < vint(texel_count); + lane_ids += vint(ASTCENC_SIMD_WIDTH); + + // Compute the error that arises from just ditching alpha + vfloat data_a = gatherf(blk.data_a, tix); + vfloat alpha_diff = data_a - default_a; + alpha_diff = alpha_diff * alpha_diff; + + haccumulate(a_drop_errv, alpha_diff, mask); + + vfloat data_r = gatherf(blk.data_r, tix); + vfloat data_g = gatherf(blk.data_g, tix); + vfloat data_b = gatherf(blk.data_b, tix); + + // Compute uncorrelated error + vfloat param = data_r * uncor_bs0 + + data_g * uncor_bs1 + + data_b * uncor_bs2; + + vfloat dist0 = (uncor_amod0 + param * uncor_bs0) - data_r; + vfloat dist1 = (uncor_amod1 + param * uncor_bs1) - data_g; + vfloat dist2 = (uncor_amod2 + param * uncor_bs2) - data_b; + + vfloat error = dist0 * dist0 * ews.lane<0>() + + dist1 * dist1 * ews.lane<1>() + + dist2 * dist2 * ews.lane<2>(); + + haccumulate(uncor_errv, error, mask); + + // Compute same chroma error - no "amod", its always zero + param = data_r * samec_bs0 + + data_g * samec_bs1 + + data_b * samec_bs2; + + dist0 = (param * samec_bs0) - data_r; + dist1 = (param * samec_bs1) - data_g; + dist2 = (param * samec_bs2) - data_b; + + error = dist0 * dist0 * ews.lane<0>() + + dist1 * dist1 * ews.lane<1>() + + dist2 * dist2 * ews.lane<2>(); + + haccumulate(samec_errv, error, mask); + + // Compute rgbl error + param = data_r * rgbl_bs0 + + data_g * rgbl_bs1 + + data_b * rgbl_bs2; + + dist0 = (rgbl_amod0 + param * rgbl_bs0) - data_r; + dist1 = (rgbl_amod1 + param * rgbl_bs1) - data_g; + dist2 = (rgbl_amod2 + param * rgbl_bs2) - data_b; + + error = dist0 * dist0 * ews.lane<0>() + + dist1 * dist1 * ews.lane<1>() + + dist2 * dist2 * ews.lane<2>(); + + haccumulate(rgbl_errv, error, mask); + + // Compute luma error - no "amod", its always zero + param = data_r * l_bs0 + + data_g * l_bs1 + + data_b * l_bs2; + + dist0 = (param * l_bs0) - data_r; + dist1 = (param * l_bs1) - data_g; + dist2 = (param * l_bs2) - data_b; + + error = dist0 * dist0 * ews.lane<0>() + + dist1 * dist1 * ews.lane<1>() + + dist2 * dist2 * ews.lane<2>(); + + haccumulate(l_errv, error, mask); + } + + a_drop_err = hadd_s(a_drop_errv) * ews.lane<3>(); + uncor_err = hadd_s(uncor_errv); + samec_err = hadd_s(samec_errv); + rgbl_err = hadd_s(rgbl_errv); + l_err = hadd_s(l_errv); +} + +/** + * @brief For a given set of input colors and partitioning determine endpoint encode errors. + * + * This function determines the color error that results from RGB-scale encoding (LDR only), + * RGB-lumashift encoding (HDR only), luminance-encoding, and alpha drop. Also determines whether + * the endpoints are eligible for offset encoding or blue-contraction + * + * @param blk The image block. + * @param pi The partition info data. + * @param ep The idealized endpoints. + * @param[out] eci The resulting encoding choice error metrics. + */ +static void compute_encoding_choice_errors( + const image_block& blk, + const partition_info& pi, + const endpoints& ep, + encoding_choice_errors eci[BLOCK_MAX_PARTITIONS]) +{ + int partition_count = pi.partition_count; + promise(partition_count > 0); + + partition_metrics pms[BLOCK_MAX_PARTITIONS]; + + compute_avgs_and_dirs_3_comp_rgb(pi, blk, pms); + + for (int i = 0; i < partition_count; i++) + { + partition_metrics& pm = pms[i]; + + line3 uncor_rgb_lines; + line3 samec_rgb_lines; // for LDR-RGB-scale + line3 rgb_luma_lines; // for HDR-RGB-scale + + processed_line3 uncor_rgb_plines; + processed_line3 samec_rgb_plines; + processed_line3 rgb_luma_plines; + processed_line3 luminance_plines; + + float uncorr_rgb_error; + float samechroma_rgb_error; + float rgb_luma_error; + float luminance_rgb_error; + float alpha_drop_error; + + uncor_rgb_lines.a = pm.avg; + uncor_rgb_lines.b = normalize_safe(pm.dir, unit3()); + + samec_rgb_lines.a = vfloat4::zero(); + samec_rgb_lines.b = normalize_safe(pm.avg, unit3()); + + rgb_luma_lines.a = pm.avg; + rgb_luma_lines.b = unit3(); + + uncor_rgb_plines.amod = uncor_rgb_lines.a - uncor_rgb_lines.b * dot3(uncor_rgb_lines.a, uncor_rgb_lines.b); + uncor_rgb_plines.bs = uncor_rgb_lines.b; + + // Same chroma always goes though zero, so this is simpler than the others + samec_rgb_plines.amod = vfloat4::zero(); + samec_rgb_plines.bs = samec_rgb_lines.b; + + rgb_luma_plines.amod = rgb_luma_lines.a - rgb_luma_lines.b * dot3(rgb_luma_lines.a, rgb_luma_lines.b); + rgb_luma_plines.bs = rgb_luma_lines.b; + + // Luminance always goes though zero, so this is simpler than the others + luminance_plines.amod = vfloat4::zero(); + luminance_plines.bs = unit3(); + + compute_error_squared_rgb_single_partition( + pi, i, blk, + uncor_rgb_plines, uncorr_rgb_error, + samec_rgb_plines, samechroma_rgb_error, + rgb_luma_plines, rgb_luma_error, + luminance_plines, luminance_rgb_error, + alpha_drop_error); + + // Determine if we can offset encode RGB lanes + vfloat4 endpt0 = ep.endpt0[i]; + vfloat4 endpt1 = ep.endpt1[i]; + vfloat4 endpt_diff = abs(endpt1 - endpt0); + vmask4 endpt_can_offset = endpt_diff < vfloat4(0.12f * 65535.0f); + bool can_offset_encode = (mask(endpt_can_offset) & 0x7) == 0x7; + + // Store out the settings + eci[i].rgb_scale_error = (samechroma_rgb_error - uncorr_rgb_error) * 0.7f; // empirical + eci[i].rgb_luma_error = (rgb_luma_error - uncorr_rgb_error) * 1.5f; // wild guess + eci[i].luminance_error = (luminance_rgb_error - uncorr_rgb_error) * 3.0f; // empirical + eci[i].alpha_drop_error = alpha_drop_error * 3.0f; + eci[i].can_offset_encode = can_offset_encode; + eci[i].can_blue_contract = !blk.is_luminance(); + } +} + +/** + * @brief For a given partition compute the error for every endpoint integer count and quant level. + * + * @param encode_hdr_rgb @c true if using HDR for RGB, @c false for LDR. + * @param encode_hdr_alpha @c true if using HDR for alpha, @c false for LDR. + * @param partition_index The partition index. + * @param pi The partition info. + * @param eci The encoding choice error metrics. + * @param ep The idealized endpoints. + * @param error_weight The resulting encoding choice error metrics. + * @param[out] best_error The best error for each integer count and quant level. + * @param[out] format_of_choice The preferred endpoint format for each integer count and quant level. + */ +static void compute_color_error_for_every_integer_count_and_quant_level( + bool encode_hdr_rgb, + bool encode_hdr_alpha, + int partition_index, + const partition_info& pi, + const encoding_choice_errors& eci, + const endpoints& ep, + vfloat4 error_weight, + float best_error[21][4], + uint8_t format_of_choice[21][4] +) { + int partition_size = pi.partition_texel_count[partition_index]; + + static const float baseline_quant_error[21 - QUANT_6] { + (65536.0f * 65536.0f / 18.0f) / (5 * 5), + (65536.0f * 65536.0f / 18.0f) / (7 * 7), + (65536.0f * 65536.0f / 18.0f) / (9 * 9), + (65536.0f * 65536.0f / 18.0f) / (11 * 11), + (65536.0f * 65536.0f / 18.0f) / (15 * 15), + (65536.0f * 65536.0f / 18.0f) / (19 * 19), + (65536.0f * 65536.0f / 18.0f) / (23 * 23), + (65536.0f * 65536.0f / 18.0f) / (31 * 31), + (65536.0f * 65536.0f / 18.0f) / (39 * 39), + (65536.0f * 65536.0f / 18.0f) / (47 * 47), + (65536.0f * 65536.0f / 18.0f) / (63 * 63), + (65536.0f * 65536.0f / 18.0f) / (79 * 79), + (65536.0f * 65536.0f / 18.0f) / (95 * 95), + (65536.0f * 65536.0f / 18.0f) / (127 * 127), + (65536.0f * 65536.0f / 18.0f) / (159 * 159), + (65536.0f * 65536.0f / 18.0f) / (191 * 191), + (65536.0f * 65536.0f / 18.0f) / (255 * 255) + }; + + vfloat4 ep0 = ep.endpt0[partition_index]; + vfloat4 ep1 = ep.endpt1[partition_index]; + + float ep1_min = hmin_rgb_s(ep1); + ep1_min = astc::max(ep1_min, 0.0f); + + float error_weight_rgbsum = hadd_rgb_s(error_weight); + + float range_upper_limit_rgb = encode_hdr_rgb ? 61440.0f : 65535.0f; + float range_upper_limit_alpha = encode_hdr_alpha ? 61440.0f : 65535.0f; + + // It is possible to get endpoint colors significantly outside [0,upper-limit] even if the + // input data are safely contained in [0,upper-limit]; we need to add an error term for this + vfloat4 offset(range_upper_limit_rgb, range_upper_limit_rgb, range_upper_limit_rgb, range_upper_limit_alpha); + vfloat4 ep0_range_error_high = max(ep0 - offset, 0.0f); + vfloat4 ep1_range_error_high = max(ep1 - offset, 0.0f); + + vfloat4 ep0_range_error_low = min(ep0, 0.0f); + vfloat4 ep1_range_error_low = min(ep1, 0.0f); + + vfloat4 sum_range_error = + (ep0_range_error_low * ep0_range_error_low) + + (ep1_range_error_low * ep1_range_error_low) + + (ep0_range_error_high * ep0_range_error_high) + + (ep1_range_error_high * ep1_range_error_high); + + float rgb_range_error = dot3_s(sum_range_error, error_weight) + * 0.5f * static_cast<float>(partition_size); + float alpha_range_error = sum_range_error.lane<3>() * error_weight.lane<3>() + * 0.5f * static_cast<float>(partition_size); + + if (encode_hdr_rgb) + { + + // Collect some statistics + float af, cf; + if (ep1.lane<0>() > ep1.lane<1>() && ep1.lane<0>() > ep1.lane<2>()) + { + af = ep1.lane<0>(); + cf = ep1.lane<0>() - ep0.lane<0>(); + } + else if (ep1.lane<1>() > ep1.lane<2>()) + { + af = ep1.lane<1>(); + cf = ep1.lane<1>() - ep0.lane<1>(); + } + else + { + af = ep1.lane<2>(); + cf = ep1.lane<2>() - ep0.lane<2>(); + } + + // Estimate of color-component spread in high endpoint color + float bf = af - ep1_min; + vfloat4 prd = (ep1 - vfloat4(cf)).swz<0, 1, 2>(); + vfloat4 pdif = prd - ep0.swz<0, 1, 2>(); + // Estimate of color-component spread in low endpoint color + float df = hmax_s(abs(pdif)); + + int b = static_cast<int>(bf); + int c = static_cast<int>(cf); + int d = static_cast<int>(df); + + // Determine which one of the 6 submodes is likely to be used in case of an RGBO-mode + int rgbo_mode = 5; // 7 bits per component + // mode 4: 8 7 6 + if (b < 32768 && c < 16384) + { + rgbo_mode = 4; + } + + // mode 3: 9 6 7 + if (b < 8192 && c < 16384) + { + rgbo_mode = 3; + } + + // mode 2: 10 5 8 + if (b < 2048 && c < 16384) + { + rgbo_mode = 2; + } + + // mode 1: 11 6 5 + if (b < 2048 && c < 1024) + { + rgbo_mode = 1; + } + + // mode 0: 11 5 7 + if (b < 1024 && c < 4096) + { + rgbo_mode = 0; + } + + // Determine which one of the 9 submodes is likely to be used in case of an RGB-mode. + int rgb_mode = 8; // 8 bits per component, except 7 bits for blue + + // mode 0: 9 7 6 7 + if (b < 16384 && c < 8192 && d < 8192) + { + rgb_mode = 0; + } + + // mode 1: 9 8 6 6 + if (b < 32768 && c < 8192 && d < 4096) + { + rgb_mode = 1; + } + + // mode 2: 10 6 7 7 + if (b < 4096 && c < 8192 && d < 4096) + { + rgb_mode = 2; + } + + // mode 3: 10 7 7 6 + if (b < 8192 && c < 8192 && d < 2048) + { + rgb_mode = 3; + } + + // mode 4: 11 8 6 5 + if (b < 8192 && c < 2048 && d < 512) + { + rgb_mode = 4; + } + + // mode 5: 11 6 8 6 + if (b < 2048 && c < 8192 && d < 1024) + { + rgb_mode = 5; + } + + // mode 6: 12 7 7 5 + if (b < 2048 && c < 2048 && d < 256) + { + rgb_mode = 6; + } + + // mode 7: 12 6 7 6 + if (b < 1024 && c < 2048 && d < 512) + { + rgb_mode = 7; + } + + static const float rgbo_error_scales[6] { 4.0f, 4.0f, 16.0f, 64.0f, 256.0f, 1024.0f }; + static const float rgb_error_scales[9] { 64.0f, 64.0f, 16.0f, 16.0f, 4.0f, 4.0f, 1.0f, 1.0f, 384.0f }; + + float mode7mult = rgbo_error_scales[rgbo_mode] * 0.0015f; // Empirically determined .... + float mode11mult = rgb_error_scales[rgb_mode] * 0.010f; // Empirically determined .... + + + float lum_high = hadd_rgb_s(ep1) * (1.0f / 3.0f); + float lum_low = hadd_rgb_s(ep0) * (1.0f / 3.0f); + float lumdif = lum_high - lum_low; + float mode23mult = lumdif < 960 ? 4.0f : lumdif < 3968 ? 16.0f : 128.0f; + + mode23mult *= 0.0005f; // Empirically determined .... + + // Pick among the available HDR endpoint modes + for (int i = QUANT_2; i < QUANT_16; i++) + { + best_error[i][3] = ERROR_CALC_DEFAULT; + best_error[i][2] = ERROR_CALC_DEFAULT; + best_error[i][1] = ERROR_CALC_DEFAULT; + best_error[i][0] = ERROR_CALC_DEFAULT; + + format_of_choice[i][3] = static_cast<uint8_t>(encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA); + format_of_choice[i][2] = FMT_HDR_RGB; + format_of_choice[i][1] = FMT_HDR_RGB_SCALE; + format_of_choice[i][0] = FMT_HDR_LUMINANCE_LARGE_RANGE; + } + + for (int i = QUANT_16; i <= QUANT_256; i++) + { + // The base_quant_error should depend on the scale-factor that would be used during + // actual encode of the color value + + float base_quant_error = baseline_quant_error[i - QUANT_6] * static_cast<float>(partition_size); + float rgb_quantization_error = error_weight_rgbsum * base_quant_error * 2.0f; + float alpha_quantization_error = error_weight.lane<3>() * base_quant_error * 2.0f; + float rgba_quantization_error = rgb_quantization_error + alpha_quantization_error; + + // For 8 integers, we have two encodings: one with HDR A and another one with LDR A + + float full_hdr_rgba_error = rgba_quantization_error + rgb_range_error + alpha_range_error; + best_error[i][3] = full_hdr_rgba_error; + format_of_choice[i][3] = static_cast<uint8_t>(encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA); + + // For 6 integers, we have one HDR-RGB encoding + float full_hdr_rgb_error = (rgb_quantization_error * mode11mult) + rgb_range_error + eci.alpha_drop_error; + best_error[i][2] = full_hdr_rgb_error; + format_of_choice[i][2] = FMT_HDR_RGB; + + // For 4 integers, we have one HDR-RGB-Scale encoding + float hdr_rgb_scale_error = (rgb_quantization_error * mode7mult) + rgb_range_error + eci.alpha_drop_error + eci.rgb_luma_error; + + best_error[i][1] = hdr_rgb_scale_error; + format_of_choice[i][1] = FMT_HDR_RGB_SCALE; + + // For 2 integers, we assume luminance-with-large-range + float hdr_luminance_error = (rgb_quantization_error * mode23mult) + rgb_range_error + eci.alpha_drop_error + eci.luminance_error; + best_error[i][0] = hdr_luminance_error; + format_of_choice[i][0] = FMT_HDR_LUMINANCE_LARGE_RANGE; + } + } + else + { + for (int i = QUANT_2; i < QUANT_6; i++) + { + best_error[i][3] = ERROR_CALC_DEFAULT; + best_error[i][2] = ERROR_CALC_DEFAULT; + best_error[i][1] = ERROR_CALC_DEFAULT; + best_error[i][0] = ERROR_CALC_DEFAULT; + + format_of_choice[i][3] = FMT_RGBA; + format_of_choice[i][2] = FMT_RGB; + format_of_choice[i][1] = FMT_RGB_SCALE; + format_of_choice[i][0] = FMT_LUMINANCE; + } + + float base_quant_error_rgb = error_weight_rgbsum * static_cast<float>(partition_size); + float base_quant_error_a = error_weight.lane<3>() * static_cast<float>(partition_size); + float base_quant_error_rgba = base_quant_error_rgb + base_quant_error_a; + + float error_scale_bc_rgba = eci.can_blue_contract ? 0.625f : 1.0f; + float error_scale_oe_rgba = eci.can_offset_encode ? 0.5f : 1.0f; + + float error_scale_bc_rgb = eci.can_blue_contract ? 0.5f : 1.0f; + float error_scale_oe_rgb = eci.can_offset_encode ? 0.25f : 1.0f; + + // Pick among the available LDR endpoint modes + for (int i = QUANT_6; i <= QUANT_256; i++) + { + // Offset encoding not possible at higher quant levels + if (i >= QUANT_192) + { + error_scale_oe_rgba = 1.0f; + error_scale_oe_rgb = 1.0f; + } + + float base_quant_error = baseline_quant_error[i - QUANT_6]; + float quant_error_rgb = base_quant_error_rgb * base_quant_error; + float quant_error_rgba = base_quant_error_rgba * base_quant_error; + + // 8 integers can encode as RGBA+RGBA + float full_ldr_rgba_error = quant_error_rgba + * error_scale_bc_rgba + * error_scale_oe_rgba + + rgb_range_error + + alpha_range_error; + + best_error[i][3] = full_ldr_rgba_error; + format_of_choice[i][3] = FMT_RGBA; + + // 6 integers can encode as RGB+RGB or RGBS+AA + float full_ldr_rgb_error = quant_error_rgb + * error_scale_bc_rgb + * error_scale_oe_rgb + + rgb_range_error + + eci.alpha_drop_error; + + float rgbs_alpha_error = quant_error_rgba + + eci.rgb_scale_error + + rgb_range_error + + alpha_range_error; + + if (rgbs_alpha_error < full_ldr_rgb_error) + { + best_error[i][2] = rgbs_alpha_error; + format_of_choice[i][2] = FMT_RGB_SCALE_ALPHA; + } + else + { + best_error[i][2] = full_ldr_rgb_error; + format_of_choice[i][2] = FMT_RGB; + } + + // 4 integers can encode as RGBS or LA+LA + float ldr_rgbs_error = quant_error_rgb + + rgb_range_error + + eci.alpha_drop_error + + eci.rgb_scale_error; + + float lum_alpha_error = quant_error_rgba + + rgb_range_error + + alpha_range_error + + eci.luminance_error; + + if (ldr_rgbs_error < lum_alpha_error) + { + best_error[i][1] = ldr_rgbs_error; + format_of_choice[i][1] = FMT_RGB_SCALE; + } + else + { + best_error[i][1] = lum_alpha_error; + format_of_choice[i][1] = FMT_LUMINANCE_ALPHA; + } + + // 2 integers can encode as L+L + float luminance_error = quant_error_rgb + + rgb_range_error + + eci.alpha_drop_error + + eci.luminance_error; + + best_error[i][0] = luminance_error; + format_of_choice[i][0] = FMT_LUMINANCE; + } + } +} + +/** + * @brief For one partition compute the best format and quantization for a given bit count. + * + * @param best_combined_error The best error for each quant level and integer count. + * @param best_combined_format The best format for each quant level and integer count. + * @param bits_available The number of bits available for encoding. + * @param[out] best_quant_level The output best color quant level. + * @param[out] best_format The output best color format. + * + * @return The output error for the best pairing. + */ +static float one_partition_find_best_combination_for_bitcount( + const float best_combined_error[21][4], + const uint8_t best_combined_format[21][4], + int bits_available, + uint8_t& best_quant_level, + uint8_t& best_format +) { + int best_integer_count = 0; + float best_integer_count_error = ERROR_CALC_DEFAULT; + + for (int integer_count = 1; integer_count <= 4; integer_count++) + { + // Compute the quantization level for a given number of integers and a given number of bits + int quant_level = quant_mode_table[integer_count][bits_available]; + + // Don't have enough bits to represent a given endpoint format at all! + if (quant_level < QUANT_6) + { + continue; + } + + float integer_count_error = best_combined_error[quant_level][integer_count - 1]; + if (integer_count_error < best_integer_count_error) + { + best_integer_count_error = integer_count_error; + best_integer_count = integer_count - 1; + } + } + + int ql = quant_mode_table[best_integer_count + 1][bits_available]; + + best_quant_level = static_cast<uint8_t>(ql); + best_format = FMT_LUMINANCE; + + if (ql >= QUANT_6) + { + best_format = best_combined_format[ql][best_integer_count]; + } + + return best_integer_count_error; +} + +/** + * @brief For 2 partitions compute the best format combinations for every pair of quant mode and integer count. + * + * @param best_error The best error for a single endpoint quant level and integer count. + * @param best_format The best format for a single endpoint quant level and integer count. + * @param[out] best_combined_error The best combined error pairings for the 2 partitions. + * @param[out] best_combined_format The best combined format pairings for the 2 partitions. + */ +static void two_partitions_find_best_combination_for_every_quantization_and_integer_count( + const float best_error[2][21][4], // indexed by (partition, quant-level, integer-pair-count-minus-1) + const uint8_t best_format[2][21][4], + float best_combined_error[21][7], // indexed by (quant-level, integer-pair-count-minus-2) + uint8_t best_combined_format[21][7][2] +) { + for (int i = QUANT_2; i <= QUANT_256; i++) + { + for (int j = 0; j < 7; j++) + { + best_combined_error[i][j] = ERROR_CALC_DEFAULT; + } + } + + for (int quant = QUANT_6; quant <= QUANT_256; quant++) + { + for (int i = 0; i < 4; i++) // integer-count for first endpoint-pair + { + for (int j = 0; j < 4; j++) // integer-count for second endpoint-pair + { + int low2 = astc::min(i, j); + int high2 = astc::max(i, j); + if ((high2 - low2) > 1) + { + continue; + } + + int intcnt = i + j; + float errorterm = astc::min(best_error[0][quant][i] + best_error[1][quant][j], 1e10f); + if (errorterm <= best_combined_error[quant][intcnt]) + { + best_combined_error[quant][intcnt] = errorterm; + best_combined_format[quant][intcnt][0] = best_format[0][quant][i]; + best_combined_format[quant][intcnt][1] = best_format[1][quant][j]; + } + } + } + } +} + +/** + * @brief For 2 partitions compute the best format and quantization for a given bit count. + * + * @param best_combined_error The best error for each quant level and integer count. + * @param best_combined_format The best format for each quant level and integer count. + * @param bits_available The number of bits available for encoding. + * @param[out] best_quant_level The output best color quant level. + * @param[out] best_quant_level_mod The output best color quant level assuming two more bits are available. + * @param[out] best_formats The output best color formats. + * + * @return The output error for the best pairing. + */ +static float two_partitions_find_best_combination_for_bitcount( + float best_combined_error[21][7], + uint8_t best_combined_format[21][7][2], + int bits_available, + uint8_t& best_quant_level, + uint8_t& best_quant_level_mod, + uint8_t* best_formats +) { + int best_integer_count = 0; + float best_integer_count_error = ERROR_CALC_DEFAULT; + + for (int integer_count = 2; integer_count <= 8; integer_count++) + { + // Compute the quantization level for a given number of integers and a given number of bits + int quant_level = quant_mode_table[integer_count][bits_available]; + + // Don't have enough bits to represent a given endpoint format at all! + if (quant_level < QUANT_6) + { + break; + } + + float integer_count_error = best_combined_error[quant_level][integer_count - 2]; + if (integer_count_error < best_integer_count_error) + { + best_integer_count_error = integer_count_error; + best_integer_count = integer_count; + } + } + + int ql = quant_mode_table[best_integer_count][bits_available]; + int ql_mod = quant_mode_table[best_integer_count][bits_available + 2]; + + best_quant_level = static_cast<uint8_t>(ql); + best_quant_level_mod = static_cast<uint8_t>(ql_mod); + + if (ql >= QUANT_6) + { + for (int i = 0; i < 2; i++) + { + best_formats[i] = best_combined_format[ql][best_integer_count - 2][i]; + } + } + else + { + for (int i = 0; i < 2; i++) + { + best_formats[i] = FMT_LUMINANCE; + } + } + + return best_integer_count_error; +} + +/** + * @brief For 3 partitions compute the best format combinations for every pair of quant mode and integer count. + * + * @param best_error The best error for a single endpoint quant level and integer count. + * @param best_format The best format for a single endpoint quant level and integer count. + * @param[out] best_combined_error The best combined error pairings for the 3 partitions. + * @param[out] best_combined_format The best combined format pairings for the 3 partitions. + */ +static void three_partitions_find_best_combination_for_every_quantization_and_integer_count( + const float best_error[3][21][4], // indexed by (partition, quant-level, integer-count) + const uint8_t best_format[3][21][4], + float best_combined_error[21][10], + uint8_t best_combined_format[21][10][3] +) { + for (int i = QUANT_2; i <= QUANT_256; i++) + { + for (int j = 0; j < 10; j++) + { + best_combined_error[i][j] = ERROR_CALC_DEFAULT; + } + } + + for (int quant = QUANT_6; quant <= QUANT_256; quant++) + { + for (int i = 0; i < 4; i++) // integer-count for first endpoint-pair + { + for (int j = 0; j < 4; j++) // integer-count for second endpoint-pair + { + int low2 = astc::min(i, j); + int high2 = astc::max(i, j); + if ((high2 - low2) > 1) + { + continue; + } + + for (int k = 0; k < 4; k++) // integer-count for third endpoint-pair + { + int low3 = astc::min(k, low2); + int high3 = astc::max(k, high2); + if ((high3 - low3) > 1) + { + continue; + } + + int intcnt = i + j + k; + float errorterm = astc::min(best_error[0][quant][i] + best_error[1][quant][j] + best_error[2][quant][k], 1e10f); + if (errorterm <= best_combined_error[quant][intcnt]) + { + best_combined_error[quant][intcnt] = errorterm; + best_combined_format[quant][intcnt][0] = best_format[0][quant][i]; + best_combined_format[quant][intcnt][1] = best_format[1][quant][j]; + best_combined_format[quant][intcnt][2] = best_format[2][quant][k]; + } + } + } + } + } +} + +/** + * @brief For 3 partitions compute the best format and quantization for a given bit count. + * + * @param best_combined_error The best error for each quant level and integer count. + * @param best_combined_format The best format for each quant level and integer count. + * @param bits_available The number of bits available for encoding. + * @param[out] best_quant_level The output best color quant level. + * @param[out] best_quant_level_mod The output best color quant level assuming two more bits are available. + * @param[out] best_formats The output best color formats. + * + * @return The output error for the best pairing. + */ +static float three_partitions_find_best_combination_for_bitcount( + const float best_combined_error[21][10], + const uint8_t best_combined_format[21][10][3], + int bits_available, + uint8_t& best_quant_level, + uint8_t& best_quant_level_mod, + uint8_t* best_formats +) { + int best_integer_count = 0; + float best_integer_count_error = ERROR_CALC_DEFAULT; + + for (int integer_count = 3; integer_count <= 9; integer_count++) + { + // Compute the quantization level for a given number of integers and a given number of bits + int quant_level = quant_mode_table[integer_count][bits_available]; + + // Don't have enough bits to represent a given endpoint format at all! + if (quant_level < QUANT_6) + { + break; + } + + float integer_count_error = best_combined_error[quant_level][integer_count - 3]; + if (integer_count_error < best_integer_count_error) + { + best_integer_count_error = integer_count_error; + best_integer_count = integer_count; + } + } + + int ql = quant_mode_table[best_integer_count][bits_available]; + int ql_mod = quant_mode_table[best_integer_count][bits_available + 5]; + + best_quant_level = static_cast<uint8_t>(ql); + best_quant_level_mod = static_cast<uint8_t>(ql_mod); + + if (ql >= QUANT_6) + { + for (int i = 0; i < 3; i++) + { + best_formats[i] = best_combined_format[ql][best_integer_count - 3][i]; + } + } + else + { + for (int i = 0; i < 3; i++) + { + best_formats[i] = FMT_LUMINANCE; + } + } + + return best_integer_count_error; +} + +/** + * @brief For 4 partitions compute the best format combinations for every pair of quant mode and integer count. + * + * @param best_error The best error for a single endpoint quant level and integer count. + * @param best_format The best format for a single endpoint quant level and integer count. + * @param[out] best_combined_error The best combined error pairings for the 4 partitions. + * @param[out] best_combined_format The best combined format pairings for the 4 partitions. + */ +static void four_partitions_find_best_combination_for_every_quantization_and_integer_count( + const float best_error[4][21][4], // indexed by (partition, quant-level, integer-count) + const uint8_t best_format[4][21][4], + float best_combined_error[21][13], + uint8_t best_combined_format[21][13][4] +) { + for (int i = QUANT_2; i <= QUANT_256; i++) + { + for (int j = 0; j < 13; j++) + { + best_combined_error[i][j] = ERROR_CALC_DEFAULT; + } + } + + for (int quant = QUANT_6; quant <= QUANT_256; quant++) + { + for (int i = 0; i < 4; i++) // integer-count for first endpoint-pair + { + for (int j = 0; j < 4; j++) // integer-count for second endpoint-pair + { + int low2 = astc::min(i, j); + int high2 = astc::max(i, j); + if ((high2 - low2) > 1) + { + continue; + } + + for (int k = 0; k < 4; k++) // integer-count for third endpoint-pair + { + int low3 = astc::min(k, low2); + int high3 = astc::max(k, high2); + if ((high3 - low3) > 1) + { + continue; + } + + for (int l = 0; l < 4; l++) // integer-count for fourth endpoint-pair + { + int low4 = astc::min(l, low3); + int high4 = astc::max(l, high3); + if ((high4 - low4) > 1) + { + continue; + } + + int intcnt = i + j + k + l; + float errorterm = astc::min(best_error[0][quant][i] + best_error[1][quant][j] + best_error[2][quant][k] + best_error[3][quant][l], 1e10f); + if (errorterm <= best_combined_error[quant][intcnt]) + { + best_combined_error[quant][intcnt] = errorterm; + best_combined_format[quant][intcnt][0] = best_format[0][quant][i]; + best_combined_format[quant][intcnt][1] = best_format[1][quant][j]; + best_combined_format[quant][intcnt][2] = best_format[2][quant][k]; + best_combined_format[quant][intcnt][3] = best_format[3][quant][l]; + } + } + } + } + } + } +} + +/** + * @brief For 4 partitions compute the best format and quantization for a given bit count. + * + * @param best_combined_error The best error for each quant level and integer count. + * @param best_combined_format The best format for each quant level and integer count. + * @param bits_available The number of bits available for encoding. + * @param[out] best_quant_level The output best color quant level. + * @param[out] best_quant_level_mod The output best color quant level assuming two more bits are available. + * @param[out] best_formats The output best color formats. + * + * @return best_error The output error for the best pairing. + */ +static float four_partitions_find_best_combination_for_bitcount( + const float best_combined_error[21][13], + const uint8_t best_combined_format[21][13][4], + int bits_available, + uint8_t& best_quant_level, + uint8_t& best_quant_level_mod, + uint8_t* best_formats +) { + int best_integer_count = 0; + float best_integer_count_error = ERROR_CALC_DEFAULT; + + for (int integer_count = 4; integer_count <= 9; integer_count++) + { + // Compute the quantization level for a given number of integers and a given number of bits + int quant_level = quant_mode_table[integer_count][bits_available]; + + // Don't have enough bits to represent a given endpoint format at all! + if (quant_level < QUANT_6) + { + break; + } + + float integer_count_error = best_combined_error[quant_level][integer_count - 4]; + if (integer_count_error < best_integer_count_error) + { + best_integer_count_error = integer_count_error; + best_integer_count = integer_count; + } + } + + int ql = quant_mode_table[best_integer_count][bits_available]; + int ql_mod = quant_mode_table[best_integer_count][bits_available + 8]; + + best_quant_level = static_cast<uint8_t>(ql); + best_quant_level_mod = static_cast<uint8_t>(ql_mod); + + if (ql >= QUANT_6) + { + for (int i = 0; i < 4; i++) + { + best_formats[i] = best_combined_format[ql][best_integer_count - 4][i]; + } + } + else + { + for (int i = 0; i < 4; i++) + { + best_formats[i] = FMT_LUMINANCE; + } + } + + return best_integer_count_error; +} + +/* See header for documentation. */ +unsigned int compute_ideal_endpoint_formats( + const partition_info& pi, + const image_block& blk, + const endpoints& ep, + // bitcounts and errors computed for the various quantization methods + const int8_t* qwt_bitcounts, + const float* qwt_errors, + unsigned int tune_candidate_limit, + unsigned int start_block_mode, + unsigned int end_block_mode, + // output data + uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS], + int block_mode[TUNE_MAX_TRIAL_CANDIDATES], + quant_method quant_level[TUNE_MAX_TRIAL_CANDIDATES], + quant_method quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES], + compression_working_buffers& tmpbuf +) { + int partition_count = pi.partition_count; + + promise(partition_count > 0); + + bool encode_hdr_rgb = static_cast<bool>(blk.rgb_lns[0]); + bool encode_hdr_alpha = static_cast<bool>(blk.alpha_lns[0]); + + // Compute the errors that result from various encoding choices (such as using luminance instead + // of RGB, discarding Alpha, using RGB-scale in place of two separate RGB endpoints and so on) + encoding_choice_errors eci[BLOCK_MAX_PARTITIONS]; + compute_encoding_choice_errors(blk, pi, ep, eci); + + float best_error[BLOCK_MAX_PARTITIONS][21][4]; + uint8_t format_of_choice[BLOCK_MAX_PARTITIONS][21][4]; + for (int i = 0; i < partition_count; i++) + { + compute_color_error_for_every_integer_count_and_quant_level( + encode_hdr_rgb, encode_hdr_alpha, i, + pi, eci[i], ep, blk.channel_weight, best_error[i], + format_of_choice[i]); + } + + float* errors_of_best_combination = tmpbuf.errors_of_best_combination; + uint8_t* best_quant_levels = tmpbuf.best_quant_levels; + uint8_t* best_quant_levels_mod = tmpbuf.best_quant_levels_mod; + uint8_t (&best_ep_formats)[WEIGHTS_MAX_BLOCK_MODES][BLOCK_MAX_PARTITIONS] = tmpbuf.best_ep_formats; + + // Ensure that the first iteration understep contains data that will never be picked + vfloat clear_error(ERROR_CALC_DEFAULT); + vint clear_quant(0); + + unsigned int packed_start_block_mode = round_down_to_simd_multiple_vla(start_block_mode); + storea(clear_error, errors_of_best_combination + packed_start_block_mode); + store_nbytes(clear_quant, best_quant_levels + packed_start_block_mode); + store_nbytes(clear_quant, best_quant_levels_mod + packed_start_block_mode); + + // Ensure that last iteration overstep contains data that will never be picked + unsigned int packed_end_block_mode = round_down_to_simd_multiple_vla(end_block_mode - 1); + storea(clear_error, errors_of_best_combination + packed_end_block_mode); + store_nbytes(clear_quant, best_quant_levels + packed_end_block_mode); + store_nbytes(clear_quant, best_quant_levels_mod + packed_end_block_mode); + + // Track a scalar best to avoid expensive search at least once ... + float error_of_best_combination = ERROR_CALC_DEFAULT; + int index_of_best_combination = -1; + + // The block contains 1 partition + if (partition_count == 1) + { + for (unsigned int i = start_block_mode; i < end_block_mode; i++) + { + if (qwt_errors[i] >= ERROR_CALC_DEFAULT) + { + errors_of_best_combination[i] = ERROR_CALC_DEFAULT; + continue; + } + + float error_of_best = one_partition_find_best_combination_for_bitcount( + best_error[0], format_of_choice[0], qwt_bitcounts[i], + best_quant_levels[i], best_ep_formats[i][0]); + + float total_error = error_of_best + qwt_errors[i]; + errors_of_best_combination[i] = total_error; + best_quant_levels_mod[i] = best_quant_levels[i]; + + if (total_error < error_of_best_combination) + { + error_of_best_combination = total_error; + index_of_best_combination = i; + } + } + } + // The block contains 2 partitions + else if (partition_count == 2) + { + float combined_best_error[21][7]; + uint8_t formats_of_choice[21][7][2]; + + two_partitions_find_best_combination_for_every_quantization_and_integer_count( + best_error, format_of_choice, combined_best_error, formats_of_choice); + + assert(start_block_mode == 0); + for (unsigned int i = 0; i < end_block_mode; i++) + { + if (qwt_errors[i] >= ERROR_CALC_DEFAULT) + { + errors_of_best_combination[i] = ERROR_CALC_DEFAULT; + continue; + } + + float error_of_best = two_partitions_find_best_combination_for_bitcount( + combined_best_error, formats_of_choice, qwt_bitcounts[i], + best_quant_levels[i], best_quant_levels_mod[i], + best_ep_formats[i]); + + float total_error = error_of_best + qwt_errors[i]; + errors_of_best_combination[i] = total_error; + + if (total_error < error_of_best_combination) + { + error_of_best_combination = total_error; + index_of_best_combination = i; + } + } + } + // The block contains 3 partitions + else if (partition_count == 3) + { + float combined_best_error[21][10]; + uint8_t formats_of_choice[21][10][3]; + + three_partitions_find_best_combination_for_every_quantization_and_integer_count( + best_error, format_of_choice, combined_best_error, formats_of_choice); + + assert(start_block_mode == 0); + for (unsigned int i = 0; i < end_block_mode; i++) + { + if (qwt_errors[i] >= ERROR_CALC_DEFAULT) + { + errors_of_best_combination[i] = ERROR_CALC_DEFAULT; + continue; + } + + float error_of_best = three_partitions_find_best_combination_for_bitcount( + combined_best_error, formats_of_choice, qwt_bitcounts[i], + best_quant_levels[i], best_quant_levels_mod[i], + best_ep_formats[i]); + + float total_error = error_of_best + qwt_errors[i]; + errors_of_best_combination[i] = total_error; + + if (total_error < error_of_best_combination) + { + error_of_best_combination = total_error; + index_of_best_combination = i; + } + } + } + // The block contains 4 partitions + else // if (partition_count == 4) + { + assert(partition_count == 4); + float combined_best_error[21][13]; + uint8_t formats_of_choice[21][13][4]; + + four_partitions_find_best_combination_for_every_quantization_and_integer_count( + best_error, format_of_choice, combined_best_error, formats_of_choice); + + assert(start_block_mode == 0); + for (unsigned int i = 0; i < end_block_mode; i++) + { + if (qwt_errors[i] >= ERROR_CALC_DEFAULT) + { + errors_of_best_combination[i] = ERROR_CALC_DEFAULT; + continue; + } + + float error_of_best = four_partitions_find_best_combination_for_bitcount( + combined_best_error, formats_of_choice, qwt_bitcounts[i], + best_quant_levels[i], best_quant_levels_mod[i], + best_ep_formats[i]); + + float total_error = error_of_best + qwt_errors[i]; + errors_of_best_combination[i] = total_error; + + if (total_error < error_of_best_combination) + { + error_of_best_combination = total_error; + index_of_best_combination = i; + } + } + } + + int best_error_weights[TUNE_MAX_TRIAL_CANDIDATES]; + + // Fast path the first result and avoid the list search for trial 0 + best_error_weights[0] = index_of_best_combination; + if (index_of_best_combination >= 0) + { + errors_of_best_combination[index_of_best_combination] = ERROR_CALC_DEFAULT; + } + + // Search the remaining results and pick the best candidate modes for trial 1+ + for (unsigned int i = 1; i < tune_candidate_limit; i++) + { + vint vbest_error_index(-1); + vfloat vbest_ep_error(ERROR_CALC_DEFAULT); + + start_block_mode = round_down_to_simd_multiple_vla(start_block_mode); + vint lane_ids = vint::lane_id() + vint(start_block_mode); + for (unsigned int j = start_block_mode; j < end_block_mode; j += ASTCENC_SIMD_WIDTH) + { + vfloat err = vfloat(errors_of_best_combination + j); + vmask mask = err < vbest_ep_error; + vbest_ep_error = select(vbest_ep_error, err, mask); + vbest_error_index = select(vbest_error_index, lane_ids, mask); + lane_ids += vint(ASTCENC_SIMD_WIDTH); + } + + // Pick best mode from the SIMD result, using lowest matching index to ensure invariance + vmask lanes_min_error = vbest_ep_error == hmin(vbest_ep_error); + vbest_error_index = select(vint(0x7FFFFFFF), vbest_error_index, lanes_min_error); + vbest_error_index = hmin(vbest_error_index); + int best_error_index = vbest_error_index.lane<0>(); + + best_error_weights[i] = best_error_index; + + // Max the error for this candidate so we don't pick it again + if (best_error_index >= 0) + { + errors_of_best_combination[best_error_index] = ERROR_CALC_DEFAULT; + } + // Early-out if no more candidates are valid + else + { + break; + } + } + + for (unsigned int i = 0; i < tune_candidate_limit; i++) + { + if (best_error_weights[i] < 0) + { + return i; + } + + block_mode[i] = best_error_weights[i]; + + quant_level[i] = static_cast<quant_method>(best_quant_levels[best_error_weights[i]]); + quant_level_mod[i] = static_cast<quant_method>(best_quant_levels_mod[best_error_weights[i]]); + + assert(quant_level[i] >= QUANT_6 && quant_level[i] <= QUANT_256); + assert(quant_level_mod[i] >= QUANT_6 && quant_level_mod[i] <= QUANT_256); + + for (int j = 0; j < partition_count; j++) + { + partition_format_specifiers[i][j] = best_ep_formats[best_error_weights[i]][j]; + } + } + + return tune_candidate_limit; +} + +#endif diff --git a/thirdparty/astcenc/astcenc_platform_isa_detection.cpp b/thirdparty/astcenc/astcenc_platform_isa_detection.cpp new file mode 100644 index 0000000000..8ed98437ea --- /dev/null +++ b/thirdparty/astcenc/astcenc_platform_isa_detection.cpp @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2020-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Platform-specific function implementations. + * + * This module contains functions for querying the host extended ISA support. + */ + +// Include before the defines below to pick up any auto-setup based on compiler +// built-in config, if not being set explicitly by the build system +#include "astcenc_internal.h" + +#if (ASTCENC_SSE > 0) || (ASTCENC_AVX > 0) || \ + (ASTCENC_POPCNT > 0) || (ASTCENC_F16C > 0) + +static bool g_init { false }; + +/** Does this CPU support SSE 4.1? Set to -1 if not yet initialized. */ +static bool g_cpu_has_sse41 { false }; + +/** Does this CPU support AVX2? Set to -1 if not yet initialized. */ +static bool g_cpu_has_avx2 { false }; + +/** Does this CPU support POPCNT? Set to -1 if not yet initialized. */ +static bool g_cpu_has_popcnt { false }; + +/** Does this CPU support F16C? Set to -1 if not yet initialized. */ +static bool g_cpu_has_f16c { false }; + +/* ============================================================================ + Platform code for Visual Studio +============================================================================ */ +#if !defined(__clang__) && defined(_MSC_VER) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <intrin.h> + +/** + * @brief Detect platform CPU ISA support and update global trackers. + */ +static void detect_cpu_isa() +{ + int data[4]; + + __cpuid(data, 0); + int num_id = data[0]; + + if (num_id >= 1) + { + __cpuidex(data, 1, 0); + // SSE41 = Bank 1, ECX, bit 19 + g_cpu_has_sse41 = data[2] & (1 << 19) ? true : false; + // POPCNT = Bank 1, ECX, bit 23 + g_cpu_has_popcnt = data[2] & (1 << 23) ? true : false; + // F16C = Bank 1, ECX, bit 29 + g_cpu_has_f16c = data[2] & (1 << 29) ? true : false; + } + + if (num_id >= 7) + { + __cpuidex(data, 7, 0); + // AVX2 = Bank 7, EBX, bit 5 + g_cpu_has_avx2 = data[1] & (1 << 5) ? true : false; + } + + // Ensure state bits are updated before init flag is updated + MemoryBarrier(); + g_init = true; +} + +/* ============================================================================ + Platform code for GCC and Clang +============================================================================ */ +#else +#include <cpuid.h> + +/** + * @brief Detect platform CPU ISA support and update global trackers. + */ +static void detect_cpu_isa() +{ + unsigned int data[4]; + + if (__get_cpuid_count(1, 0, &data[0], &data[1], &data[2], &data[3])) + { + // SSE41 = Bank 1, ECX, bit 19 + g_cpu_has_sse41 = data[2] & (1 << 19) ? true : false; + // POPCNT = Bank 1, ECX, bit 23 + g_cpu_has_popcnt = data[2] & (1 << 23) ? true : false; + // F16C = Bank 1, ECX, bit 29 + g_cpu_has_f16c = data[2] & (1 << 29) ? true : false; + } + + g_cpu_has_avx2 = 0; + if (__get_cpuid_count(7, 0, &data[0], &data[1], &data[2], &data[3])) + { + // AVX2 = Bank 7, EBX, bit 5 + g_cpu_has_avx2 = data[1] & (1 << 5) ? true : false; + } + + // Ensure state bits are updated before init flag is updated + __sync_synchronize(); + g_init = true; +} +#endif + +/* See header for documentation. */ +bool cpu_supports_popcnt() +{ + if (!g_init) + { + detect_cpu_isa(); + } + + return g_cpu_has_popcnt; +} + +/* See header for documentation. */ +bool cpu_supports_f16c() +{ + if (!g_init) + { + detect_cpu_isa(); + } + + return g_cpu_has_f16c; +} + +/* See header for documentation. */ +bool cpu_supports_sse41() +{ + if (!g_init) + { + detect_cpu_isa(); + } + + return g_cpu_has_sse41; +} + +/* See header for documentation. */ +bool cpu_supports_avx2() +{ + if (!g_init) + { + detect_cpu_isa(); + } + + return g_cpu_has_avx2; +} + +#endif diff --git a/thirdparty/astcenc/astcenc_quantization.cpp b/thirdparty/astcenc/astcenc_quantization.cpp new file mode 100644 index 0000000000..478a21ead7 --- /dev/null +++ b/thirdparty/astcenc/astcenc_quantization.cpp @@ -0,0 +1,904 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions and data tables for numeric quantization.. + */ + +#include "astcenc_internal.h" + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +// Starts from QUANT_6 +// Not scrambled +const uint8_t color_unquant_to_uquant_tables[17][256] { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, + 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, + 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, + 153, 153, 153, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 109, 109, 109, 109, + 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, + 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, 182, 219, 219, 219, 219, 219, 219, 219, + 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, + 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, + 227, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 163, 163, 163, 163, 163, 163, 163, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 232, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 232, 232, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, + 153, 153, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + 187, 187, 187, 187, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 255, 255, 255, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 148, 148, 148, + 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, + 188, 188, 188, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 228, 228, + 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 242, 242, 242, 242, 242, + 242, 242, 242, 242, 242, 242, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 211, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 211, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 255, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, + 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 41, 41, 41, 41, 41, 41, 41, 41, 49, 49, + 49, 49, 49, 49, 49, 49, 57, 57, 57, 57, 57, 57, 57, 57, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 74, 74, 74, 74, 74, 74, 74, 74, 82, + 82, 82, 82, 82, 82, 82, 82, 90, 90, 90, 90, 90, 90, 90, 90, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 107, 107, 107, 107, 107, 107, 107, 107, + 115, 115, 115, 115, 115, 115, 115, 115, 123, 123, 123, 123, 123, 123, 123, 123, + 132, 132, 132, 132, 132, 132, 132, 132, 140, 140, 140, 140, 140, 140, 140, 140, + 148, 148, 148, 148, 148, 148, 148, 148, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 165, 165, 165, 165, 165, 165, 165, 165, 173, 173, 173, 173, 173, 173, 173, + 173, 181, 181, 181, 181, 181, 181, 181, 181, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 198, 198, 198, 198, 198, 198, 198, 198, 206, 206, 206, 206, 206, 206, + 206, 206, 214, 214, 214, 214, 214, 214, 214, 214, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 231, 231, 231, 231, 231, 231, 231, 231, 239, 239, 239, 239, 239, + 239, 239, 239, 247, 247, 247, 247, 247, 247, 247, 247, 255, 255, 255, 255, 255 + }, + { + 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 13, 13, 13, 13, 13, 13, + 13, 19, 19, 19, 19, 19, 19, 26, 26, 26, 26, 26, 26, 26, 32, 32, + 32, 32, 32, 32, 39, 39, 39, 39, 39, 39, 39, 45, 45, 45, 45, 45, + 45, 52, 52, 52, 52, 52, 52, 52, 58, 58, 58, 58, 58, 58, 65, 65, + 65, 65, 65, 65, 65, 71, 71, 71, 71, 71, 71, 78, 78, 78, 78, 78, + 78, 78, 84, 84, 84, 84, 84, 84, 91, 91, 91, 91, 91, 91, 91, 97, + 97, 97, 97, 97, 97, 104, 104, 104, 104, 104, 104, 104, 110, 110, 110, 110, + 110, 110, 117, 117, 117, 117, 117, 117, 117, 123, 123, 123, 123, 123, 123, 123, + 132, 132, 132, 132, 132, 132, 132, 138, 138, 138, 138, 138, 138, 138, 145, 145, + 145, 145, 145, 145, 151, 151, 151, 151, 151, 151, 151, 158, 158, 158, 158, 158, + 158, 164, 164, 164, 164, 164, 164, 164, 171, 171, 171, 171, 171, 171, 177, 177, + 177, 177, 177, 177, 177, 184, 184, 184, 184, 184, 184, 190, 190, 190, 190, 190, + 190, 190, 197, 197, 197, 197, 197, 197, 203, 203, 203, 203, 203, 203, 203, 210, + 210, 210, 210, 210, 210, 216, 216, 216, 216, 216, 216, 216, 223, 223, 223, 223, + 223, 223, 229, 229, 229, 229, 229, 229, 229, 236, 236, 236, 236, 236, 236, 242, + 242, 242, 242, 242, 242, 242, 249, 249, 249, 249, 249, 249, 255, 255, 255, 255 + }, + { + 0, 0, 0, 5, 5, 5, 5, 5, 5, 11, 11, 11, 11, 11, 16, 16, + 16, 16, 16, 21, 21, 21, 21, 21, 21, 27, 27, 27, 27, 27, 32, 32, + 32, 32, 32, 32, 38, 38, 38, 38, 38, 43, 43, 43, 43, 43, 48, 48, + 48, 48, 48, 48, 54, 54, 54, 54, 54, 59, 59, 59, 59, 59, 59, 65, + 65, 65, 65, 65, 70, 70, 70, 70, 70, 70, 76, 76, 76, 76, 76, 81, + 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 92, 92, 92, 92, 92, 97, + 97, 97, 97, 97, 97, 103, 103, 103, 103, 103, 108, 108, 108, 108, 108, 113, + 113, 113, 113, 113, 113, 119, 119, 119, 119, 119, 124, 124, 124, 124, 124, 124, + 131, 131, 131, 131, 131, 131, 136, 136, 136, 136, 136, 142, 142, 142, 142, 142, + 142, 147, 147, 147, 147, 147, 152, 152, 152, 152, 152, 158, 158, 158, 158, 158, + 158, 163, 163, 163, 163, 163, 169, 169, 169, 169, 169, 169, 174, 174, 174, 174, + 174, 179, 179, 179, 179, 179, 185, 185, 185, 185, 185, 185, 190, 190, 190, 190, + 190, 196, 196, 196, 196, 196, 196, 201, 201, 201, 201, 201, 207, 207, 207, 207, + 207, 207, 212, 212, 212, 212, 212, 217, 217, 217, 217, 217, 223, 223, 223, 223, + 223, 223, 228, 228, 228, 228, 228, 234, 234, 234, 234, 234, 234, 239, 239, 239, + 239, 239, 244, 244, 244, 244, 244, 250, 250, 250, 250, 250, 250, 255, 255, 255 + }, + { + 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 16, + 16, 16, 16, 20, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32, + 32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 44, 44, 44, 44, 48, + 48, 48, 48, 52, 52, 52, 52, 56, 56, 56, 56, 60, 60, 60, 60, 65, + 65, 65, 65, 65, 69, 69, 69, 69, 73, 73, 73, 73, 77, 77, 77, 77, + 81, 81, 81, 81, 85, 85, 85, 85, 89, 89, 89, 89, 93, 93, 93, 93, + 97, 97, 97, 97, 101, 101, 101, 101, 105, 105, 105, 105, 109, 109, 109, 109, + 113, 113, 113, 113, 117, 117, 117, 117, 121, 121, 121, 121, 125, 125, 125, 125, + 130, 130, 130, 130, 134, 134, 134, 134, 138, 138, 138, 138, 142, 142, 142, 142, + 146, 146, 146, 146, 150, 150, 150, 150, 154, 154, 154, 154, 158, 158, 158, 158, + 162, 162, 162, 162, 166, 166, 166, 166, 170, 170, 170, 170, 174, 174, 174, 174, + 178, 178, 178, 178, 182, 182, 182, 182, 186, 186, 186, 186, 190, 190, 190, 190, + 190, 195, 195, 195, 195, 199, 199, 199, 199, 203, 203, 203, 203, 207, 207, 207, + 207, 211, 211, 211, 211, 215, 215, 215, 215, 219, 219, 219, 219, 223, 223, 223, + 223, 227, 227, 227, 227, 231, 231, 231, 231, 235, 235, 235, 235, 239, 239, 239, + 239, 243, 243, 243, 243, 247, 247, 247, 247, 251, 251, 251, 251, 255, 255, 255 + }, + { + 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9, 9, 13, 13, 13, 16, + 16, 16, 19, 19, 19, 22, 22, 22, 25, 25, 25, 25, 29, 29, 29, 32, + 32, 32, 35, 35, 35, 38, 38, 38, 38, 42, 42, 42, 45, 45, 45, 48, + 48, 48, 51, 51, 51, 54, 54, 54, 54, 58, 58, 58, 61, 61, 61, 64, + 64, 64, 67, 67, 67, 67, 71, 71, 71, 74, 74, 74, 77, 77, 77, 80, + 80, 80, 83, 83, 83, 83, 87, 87, 87, 90, 90, 90, 93, 93, 93, 96, + 96, 96, 96, 100, 100, 100, 103, 103, 103, 106, 106, 106, 109, 109, 109, 112, + 112, 112, 112, 116, 116, 116, 119, 119, 119, 122, 122, 122, 125, 125, 125, 125, + 130, 130, 130, 130, 133, 133, 133, 136, 136, 136, 139, 139, 139, 143, 143, 143, + 143, 146, 146, 146, 149, 149, 149, 152, 152, 152, 155, 155, 155, 159, 159, 159, + 159, 162, 162, 162, 165, 165, 165, 168, 168, 168, 172, 172, 172, 172, 175, 175, + 175, 178, 178, 178, 181, 181, 181, 184, 184, 184, 188, 188, 188, 188, 191, 191, + 191, 194, 194, 194, 197, 197, 197, 201, 201, 201, 201, 204, 204, 204, 207, 207, + 207, 210, 210, 210, 213, 213, 213, 217, 217, 217, 217, 220, 220, 220, 223, 223, + 223, 226, 226, 226, 230, 230, 230, 230, 233, 233, 233, 236, 236, 236, 239, 239, + 239, 242, 242, 242, 246, 246, 246, 246, 249, 249, 249, 252, 252, 252, 255, 255 + }, + { + 0, 0, 2, 2, 5, 5, 5, 8, 8, 8, 10, 10, 13, 13, 13, 16, + 16, 16, 18, 18, 21, 21, 21, 24, 24, 24, 26, 26, 29, 29, 29, 32, + 32, 32, 35, 35, 35, 37, 37, 40, 40, 40, 43, 43, 43, 45, 45, 48, + 48, 48, 51, 51, 51, 53, 53, 56, 56, 56, 59, 59, 59, 61, 61, 64, + 64, 64, 67, 67, 67, 70, 70, 70, 72, 72, 75, 75, 75, 78, 78, 78, + 80, 80, 83, 83, 83, 86, 86, 86, 88, 88, 91, 91, 91, 94, 94, 94, + 96, 96, 99, 99, 99, 102, 102, 102, 104, 104, 107, 107, 107, 110, 110, 110, + 112, 112, 115, 115, 115, 118, 118, 118, 120, 120, 123, 123, 123, 126, 126, 126, + 129, 129, 129, 132, 132, 132, 135, 135, 137, 137, 137, 140, 140, 140, 143, 143, + 145, 145, 145, 148, 148, 148, 151, 151, 153, 153, 153, 156, 156, 156, 159, 159, + 161, 161, 161, 164, 164, 164, 167, 167, 169, 169, 169, 172, 172, 172, 175, 175, + 177, 177, 177, 180, 180, 180, 183, 183, 185, 185, 185, 188, 188, 188, 191, 191, + 191, 194, 194, 196, 196, 196, 199, 199, 199, 202, 202, 204, 204, 204, 207, 207, + 207, 210, 210, 212, 212, 212, 215, 215, 215, 218, 218, 220, 220, 220, 223, 223, + 223, 226, 226, 226, 229, 229, 231, 231, 231, 234, 234, 234, 237, 237, 239, 239, + 239, 242, 242, 242, 245, 245, 247, 247, 247, 250, 250, 250, 253, 253, 255, 255 + }, + { + 0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, + 16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 26, 26, 28, 28, 30, 30, + 32, 32, 34, 34, 36, 36, 38, 38, 40, 40, 42, 42, 44, 44, 46, 46, + 48, 48, 50, 50, 52, 52, 54, 54, 56, 56, 58, 58, 60, 60, 62, 62, + 64, 64, 66, 66, 68, 68, 70, 70, 72, 72, 74, 74, 76, 76, 78, 78, + 80, 80, 82, 82, 84, 84, 86, 86, 88, 88, 90, 90, 92, 92, 94, 94, + 96, 96, 98, 98, 100, 100, 102, 102, 104, 104, 106, 106, 108, 108, 110, 110, + 112, 112, 114, 114, 116, 116, 118, 118, 120, 120, 122, 122, 124, 124, 126, 126, + 129, 129, 131, 131, 133, 133, 135, 135, 137, 137, 139, 139, 141, 141, 143, 143, + 145, 145, 147, 147, 149, 149, 151, 151, 153, 153, 155, 155, 157, 157, 159, 159, + 161, 161, 163, 163, 165, 165, 167, 167, 169, 169, 171, 171, 173, 173, 175, 175, + 177, 177, 179, 179, 181, 181, 183, 183, 185, 185, 187, 187, 189, 189, 191, 191, + 193, 193, 195, 195, 197, 197, 199, 199, 201, 201, 203, 203, 205, 205, 207, 207, + 209, 209, 211, 211, 213, 213, 215, 215, 217, 217, 219, 219, 221, 221, 223, 223, + 225, 225, 227, 227, 229, 229, 231, 231, 233, 233, 235, 235, 237, 237, 239, 239, + 241, 241, 243, 243, 245, 245, 247, 247, 249, 249, 251, 251, 253, 253, 255, 255 + }, + { + 0, 1, 1, 3, 4, 4, 6, 6, 8, 9, 9, 11, 12, 12, 14, 14, + 16, 17, 17, 19, 20, 20, 22, 22, 24, 25, 25, 27, 28, 28, 30, 30, + 32, 33, 33, 35, 36, 36, 38, 38, 40, 41, 41, 43, 44, 44, 46, 46, + 48, 49, 49, 51, 52, 52, 54, 54, 56, 57, 57, 59, 60, 60, 62, 62, + 64, 65, 65, 67, 68, 68, 70, 70, 72, 73, 73, 75, 76, 76, 78, 78, + 80, 81, 81, 83, 84, 84, 86, 86, 88, 89, 89, 91, 92, 92, 94, 94, + 96, 97, 97, 99, 100, 100, 102, 102, 104, 105, 105, 107, 108, 108, 110, 110, + 112, 113, 113, 115, 116, 116, 118, 118, 120, 121, 121, 123, 124, 124, 126, 126, + 129, 129, 131, 131, 132, 134, 134, 135, 137, 137, 139, 139, 140, 142, 142, 143, + 145, 145, 147, 147, 148, 150, 150, 151, 153, 153, 155, 155, 156, 158, 158, 159, + 161, 161, 163, 163, 164, 166, 166, 167, 169, 169, 171, 171, 172, 174, 174, 175, + 177, 177, 179, 179, 180, 182, 182, 183, 185, 185, 187, 187, 188, 190, 190, 191, + 193, 193, 195, 195, 196, 198, 198, 199, 201, 201, 203, 203, 204, 206, 206, 207, + 209, 209, 211, 211, 212, 214, 214, 215, 217, 217, 219, 219, 220, 222, 222, 223, + 225, 225, 227, 227, 228, 230, 230, 231, 233, 233, 235, 235, 236, 238, 238, 239, + 241, 241, 243, 243, 244, 246, 246, 247, 249, 249, 251, 251, 252, 254, 254, 255 + }, + { + 0, 1, 2, 2, 4, 5, 6, 6, 8, 9, 10, 10, 12, 13, 14, 14, + 16, 17, 18, 18, 20, 21, 22, 22, 24, 25, 26, 26, 28, 29, 30, 30, + 32, 33, 34, 34, 36, 37, 38, 38, 40, 41, 42, 42, 44, 45, 46, 46, + 48, 49, 50, 50, 52, 53, 54, 54, 56, 57, 58, 58, 60, 61, 62, 62, + 64, 65, 66, 66, 68, 69, 70, 70, 72, 73, 74, 74, 76, 77, 78, 78, + 80, 81, 82, 82, 84, 85, 86, 86, 88, 89, 90, 90, 92, 93, 94, 94, + 96, 97, 98, 98, 100, 101, 102, 102, 104, 105, 106, 106, 108, 109, 110, 110, + 112, 113, 114, 114, 116, 117, 118, 118, 120, 121, 122, 122, 124, 125, 126, 126, + 129, 129, 130, 131, 133, 133, 134, 135, 137, 137, 138, 139, 141, 141, 142, 143, + 145, 145, 146, 147, 149, 149, 150, 151, 153, 153, 154, 155, 157, 157, 158, 159, + 161, 161, 162, 163, 165, 165, 166, 167, 169, 169, 170, 171, 173, 173, 174, 175, + 177, 177, 178, 179, 181, 181, 182, 183, 185, 185, 186, 187, 189, 189, 190, 191, + 193, 193, 194, 195, 197, 197, 198, 199, 201, 201, 202, 203, 205, 205, 206, 207, + 209, 209, 210, 211, 213, 213, 214, 215, 217, 217, 218, 219, 221, 221, 222, 223, + 225, 225, 226, 227, 229, 229, 230, 231, 233, 233, 234, 235, 237, 237, 238, 239, + 241, 241, 242, 243, 245, 245, 246, 247, 249, 249, 250, 251, 253, 253, 254, 255 + }, + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + } +}; + +// Starts from QUANT_6 +// Scrambled +const uint8_t color_uquant_to_scrambled_pquant_tables[17][256] { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 + }, + { + 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1 + }, + { + 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1 + }, + { + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, + 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31 + }, + { + 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, + 16, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 2, 2, + 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 18, 18, 18, 18, 18, + 18, 26, 26, 26, 26, 26, 26, 26, 34, 34, 34, 34, 34, 34, 4, 4, + 4, 4, 4, 4, 4, 12, 12, 12, 12, 12, 12, 20, 20, 20, 20, 20, + 20, 20, 28, 28, 28, 28, 28, 28, 36, 36, 36, 36, 36, 36, 36, 6, + 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, 22, 22, 22, 22, + 22, 22, 30, 30, 30, 30, 30, 30, 30, 38, 38, 38, 38, 38, 38, 38, + 39, 39, 39, 39, 39, 39, 39, 31, 31, 31, 31, 31, 31, 31, 23, 23, + 23, 23, 23, 23, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, + 7, 37, 37, 37, 37, 37, 37, 37, 29, 29, 29, 29, 29, 29, 21, 21, + 21, 21, 21, 21, 21, 13, 13, 13, 13, 13, 13, 5, 5, 5, 5, 5, + 5, 5, 35, 35, 35, 35, 35, 35, 27, 27, 27, 27, 27, 27, 27, 19, + 19, 19, 19, 19, 19, 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, + 3, 3, 33, 33, 33, 33, 33, 33, 33, 25, 25, 25, 25, 25, 25, 17, + 17, 17, 17, 17, 17, 17, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1 + }, + { + 0, 0, 0, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 2, 2, + 2, 2, 2, 18, 18, 18, 18, 18, 18, 34, 34, 34, 34, 34, 4, 4, + 4, 4, 4, 4, 20, 20, 20, 20, 20, 36, 36, 36, 36, 36, 6, 6, + 6, 6, 6, 6, 22, 22, 22, 22, 22, 38, 38, 38, 38, 38, 38, 8, + 8, 8, 8, 8, 24, 24, 24, 24, 24, 24, 40, 40, 40, 40, 40, 10, + 10, 10, 10, 10, 26, 26, 26, 26, 26, 26, 42, 42, 42, 42, 42, 12, + 12, 12, 12, 12, 12, 28, 28, 28, 28, 28, 44, 44, 44, 44, 44, 14, + 14, 14, 14, 14, 14, 30, 30, 30, 30, 30, 46, 46, 46, 46, 46, 46, + 47, 47, 47, 47, 47, 47, 31, 31, 31, 31, 31, 15, 15, 15, 15, 15, + 15, 45, 45, 45, 45, 45, 29, 29, 29, 29, 29, 13, 13, 13, 13, 13, + 13, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 11, 11, 11, 11, + 11, 41, 41, 41, 41, 41, 25, 25, 25, 25, 25, 25, 9, 9, 9, 9, + 9, 39, 39, 39, 39, 39, 39, 23, 23, 23, 23, 23, 7, 7, 7, 7, + 7, 7, 37, 37, 37, 37, 37, 21, 21, 21, 21, 21, 5, 5, 5, 5, + 5, 5, 35, 35, 35, 35, 35, 19, 19, 19, 19, 19, 19, 3, 3, 3, + 3, 3, 33, 33, 33, 33, 33, 17, 17, 17, 17, 17, 17, 1, 1, 1 + }, + { + 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, + 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, + 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, + 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, + 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, + 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, + 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, + 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, + 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, + 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, + 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63 + }, + { + 0, 0, 16, 16, 16, 32, 32, 32, 48, 48, 48, 48, 64, 64, 64, 2, + 2, 2, 18, 18, 18, 34, 34, 34, 50, 50, 50, 50, 66, 66, 66, 4, + 4, 4, 20, 20, 20, 36, 36, 36, 36, 52, 52, 52, 68, 68, 68, 6, + 6, 6, 22, 22, 22, 38, 38, 38, 38, 54, 54, 54, 70, 70, 70, 8, + 8, 8, 24, 24, 24, 24, 40, 40, 40, 56, 56, 56, 72, 72, 72, 10, + 10, 10, 26, 26, 26, 26, 42, 42, 42, 58, 58, 58, 74, 74, 74, 12, + 12, 12, 12, 28, 28, 28, 44, 44, 44, 60, 60, 60, 76, 76, 76, 14, + 14, 14, 14, 30, 30, 30, 46, 46, 46, 62, 62, 62, 78, 78, 78, 78, + 79, 79, 79, 79, 63, 63, 63, 47, 47, 47, 31, 31, 31, 15, 15, 15, + 15, 77, 77, 77, 61, 61, 61, 45, 45, 45, 29, 29, 29, 13, 13, 13, + 13, 75, 75, 75, 59, 59, 59, 43, 43, 43, 27, 27, 27, 27, 11, 11, + 11, 73, 73, 73, 57, 57, 57, 41, 41, 41, 25, 25, 25, 25, 9, 9, + 9, 71, 71, 71, 55, 55, 55, 39, 39, 39, 39, 23, 23, 23, 7, 7, + 7, 69, 69, 69, 53, 53, 53, 37, 37, 37, 37, 21, 21, 21, 5, 5, + 5, 67, 67, 67, 51, 51, 51, 51, 35, 35, 35, 19, 19, 19, 3, 3, + 3, 65, 65, 65, 49, 49, 49, 49, 33, 33, 33, 17, 17, 17, 1, 1 + }, + { + 0, 0, 32, 32, 64, 64, 64, 2, 2, 2, 34, 34, 66, 66, 66, 4, + 4, 4, 36, 36, 68, 68, 68, 6, 6, 6, 38, 38, 70, 70, 70, 8, + 8, 8, 40, 40, 40, 72, 72, 10, 10, 10, 42, 42, 42, 74, 74, 12, + 12, 12, 44, 44, 44, 76, 76, 14, 14, 14, 46, 46, 46, 78, 78, 16, + 16, 16, 48, 48, 48, 80, 80, 80, 18, 18, 50, 50, 50, 82, 82, 82, + 20, 20, 52, 52, 52, 84, 84, 84, 22, 22, 54, 54, 54, 86, 86, 86, + 24, 24, 56, 56, 56, 88, 88, 88, 26, 26, 58, 58, 58, 90, 90, 90, + 28, 28, 60, 60, 60, 92, 92, 92, 30, 30, 62, 62, 62, 94, 94, 94, + 95, 95, 95, 63, 63, 63, 31, 31, 93, 93, 93, 61, 61, 61, 29, 29, + 91, 91, 91, 59, 59, 59, 27, 27, 89, 89, 89, 57, 57, 57, 25, 25, + 87, 87, 87, 55, 55, 55, 23, 23, 85, 85, 85, 53, 53, 53, 21, 21, + 83, 83, 83, 51, 51, 51, 19, 19, 81, 81, 81, 49, 49, 49, 17, 17, + 17, 79, 79, 47, 47, 47, 15, 15, 15, 77, 77, 45, 45, 45, 13, 13, + 13, 75, 75, 43, 43, 43, 11, 11, 11, 73, 73, 41, 41, 41, 9, 9, + 9, 71, 71, 71, 39, 39, 7, 7, 7, 69, 69, 69, 37, 37, 5, 5, + 5, 67, 67, 67, 35, 35, 3, 3, 3, 65, 65, 65, 33, 33, 1, 1 + }, + { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, + 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, + 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, + 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, + 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, + 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, + 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, + 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, + 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, + 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, + 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, + 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, + 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, + 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, + 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127 + }, + { + 0, 32, 32, 64, 96, 96, 128, 128, 2, 34, 34, 66, 98, 98, 130, 130, + 4, 36, 36, 68, 100, 100, 132, 132, 6, 38, 38, 70, 102, 102, 134, 134, + 8, 40, 40, 72, 104, 104, 136, 136, 10, 42, 42, 74, 106, 106, 138, 138, + 12, 44, 44, 76, 108, 108, 140, 140, 14, 46, 46, 78, 110, 110, 142, 142, + 16, 48, 48, 80, 112, 112, 144, 144, 18, 50, 50, 82, 114, 114, 146, 146, + 20, 52, 52, 84, 116, 116, 148, 148, 22, 54, 54, 86, 118, 118, 150, 150, + 24, 56, 56, 88, 120, 120, 152, 152, 26, 58, 58, 90, 122, 122, 154, 154, + 28, 60, 60, 92, 124, 124, 156, 156, 30, 62, 62, 94, 126, 126, 158, 158, + 159, 159, 127, 127, 95, 63, 63, 31, 157, 157, 125, 125, 93, 61, 61, 29, + 155, 155, 123, 123, 91, 59, 59, 27, 153, 153, 121, 121, 89, 57, 57, 25, + 151, 151, 119, 119, 87, 55, 55, 23, 149, 149, 117, 117, 85, 53, 53, 21, + 147, 147, 115, 115, 83, 51, 51, 19, 145, 145, 113, 113, 81, 49, 49, 17, + 143, 143, 111, 111, 79, 47, 47, 15, 141, 141, 109, 109, 77, 45, 45, 13, + 139, 139, 107, 107, 75, 43, 43, 11, 137, 137, 105, 105, 73, 41, 41, 9, + 135, 135, 103, 103, 71, 39, 39, 7, 133, 133, 101, 101, 69, 37, 37, 5, + 131, 131, 99, 99, 67, 35, 35, 3, 129, 129, 97, 97, 65, 33, 33, 1 + }, + { + 0, 64, 128, 128, 2, 66, 130, 130, 4, 68, 132, 132, 6, 70, 134, 134, + 8, 72, 136, 136, 10, 74, 138, 138, 12, 76, 140, 140, 14, 78, 142, 142, + 16, 80, 144, 144, 18, 82, 146, 146, 20, 84, 148, 148, 22, 86, 150, 150, + 24, 88, 152, 152, 26, 90, 154, 154, 28, 92, 156, 156, 30, 94, 158, 158, + 32, 96, 160, 160, 34, 98, 162, 162, 36, 100, 164, 164, 38, 102, 166, 166, + 40, 104, 168, 168, 42, 106, 170, 170, 44, 108, 172, 172, 46, 110, 174, 174, + 48, 112, 176, 176, 50, 114, 178, 178, 52, 116, 180, 180, 54, 118, 182, 182, + 56, 120, 184, 184, 58, 122, 186, 186, 60, 124, 188, 188, 62, 126, 190, 190, + 191, 191, 127, 63, 189, 189, 125, 61, 187, 187, 123, 59, 185, 185, 121, 57, + 183, 183, 119, 55, 181, 181, 117, 53, 179, 179, 115, 51, 177, 177, 113, 49, + 175, 175, 111, 47, 173, 173, 109, 45, 171, 171, 107, 43, 169, 169, 105, 41, + 167, 167, 103, 39, 165, 165, 101, 37, 163, 163, 99, 35, 161, 161, 97, 33, + 159, 159, 95, 31, 157, 157, 93, 29, 155, 155, 91, 27, 153, 153, 89, 25, + 151, 151, 87, 23, 149, 149, 85, 21, 147, 147, 83, 19, 145, 145, 81, 17, + 143, 143, 79, 15, 141, 141, 77, 13, 139, 139, 75, 11, 137, 137, 73, 9, + 135, 135, 71, 7, 133, 133, 69, 5, 131, 131, 67, 3, 129, 129, 65, 1 + }, + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + } +}; + +#endif + +// Starts from QUANT_6 +// Scrambled +static const uint8_t color_scrambled_pquant_to_uquant_q6[6] { + 0, 255, 51, 204, 102, 153 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q8[8] { + 0, 36, 73, 109, 146, 182, 219, 255 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q10[10] { + 0, 255, 28, 227, 56, 199, 84, 171, 113, 142 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q12[12] { + 0, 255, 69, 186, 23, 232, 92, 163, 46, 209, 116, 139 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q16[16] { + 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q20[20] { + 0, 255, 67, 188, 13, 242, 80, 175, 27, 228, 94, 161, 40, 215, 107, 148, + 54, 201, 121, 134 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q24[24] { + 0, 255, 33, 222, 66, 189, 99, 156, 11, 244, 44, 211, 77, 178, 110, 145, + 22, 233, 55, 200, 88, 167, 121, 134 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q32[32] { + 0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q40[40] { + 0, 255, 32, 223, 65, 190, 97, 158, 6, 249, 39, 216, 71, 184, 104, 151, + 13, 242, 45, 210, 78, 177, 110, 145, 19, 236, 52, 203, 84, 171, 117, 138, + 26, 229, 58, 197, 91, 164, 123, 132 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q48[48] { + 0, 255, 16, 239, 32, 223, 48, 207, 65, 190, 81, 174, 97, 158, 113, 142, + 5, 250, 21, 234, 38, 217, 54, 201, 70, 185, 86, 169, 103, 152, 119, 136, + 11, 244, 27, 228, 43, 212, 59, 196, 76, 179, 92, 163, 108, 147, 124, 131 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q64[64] { + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, + 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, + 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, + 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255, +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q80[80] { + 0, 255, 16, 239, 32, 223, 48, 207, 64, 191, 80, 175, 96, 159, 112, 143, + 3, 252, 19, 236, 35, 220, 51, 204, 67, 188, 83, 172, 100, 155, 116, 139, + 6, 249, 22, 233, 38, 217, 54, 201, 71, 184, 87, 168, 103, 152, 119, 136, + 9, 246, 25, 230, 42, 213, 58, 197, 74, 181, 90, 165, 106, 149, 122, 133, + 13, 242, 29, 226, 45, 210, 61, 194, 77, 178, 93, 162, 109, 146, 125, 130 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q96[96] { + 0, 255, 8, 247, 16, 239, 24, 231, 32, 223, 40, 215, 48, 207, 56, 199, + 64, 191, 72, 183, 80, 175, 88, 167, 96, 159, 104, 151, 112, 143, 120, 135, + 2, 253, 10, 245, 18, 237, 26, 229, 35, 220, 43, 212, 51, 204, 59, 196, + 67, 188, 75, 180, 83, 172, 91, 164, 99, 156, 107, 148, 115, 140, 123, 132, + 5, 250, 13, 242, 21, 234, 29, 226, 37, 218, 45, 210, 53, 202, 61, 194, + 70, 185, 78, 177, 86, 169, 94, 161, 102, 153, 110, 145, 118, 137, 126, 129 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q128[128] { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, + 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, + 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, + 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, + 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, + 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, + 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q160[160] { + 0, 255, 8, 247, 16, 239, 24, 231, 32, 223, 40, 215, 48, 207, 56, 199, + 64, 191, 72, 183, 80, 175, 88, 167, 96, 159, 104, 151, 112, 143, 120, 135, + 1, 254, 9, 246, 17, 238, 25, 230, 33, 222, 41, 214, 49, 206, 57, 198, + 65, 190, 73, 182, 81, 174, 89, 166, 97, 158, 105, 150, 113, 142, 121, 134, + 3, 252, 11, 244, 19, 236, 27, 228, 35, 220, 43, 212, 51, 204, 59, 196, + 67, 188, 75, 180, 83, 172, 91, 164, 99, 156, 107, 148, 115, 140, 123, 132, + 4, 251, 12, 243, 20, 235, 28, 227, 36, 219, 44, 211, 52, 203, 60, 195, + 68, 187, 76, 179, 84, 171, 92, 163, 100, 155, 108, 147, 116, 139, 124, 131, + 6, 249, 14, 241, 22, 233, 30, 225, 38, 217, 46, 209, 54, 201, 62, 193, + 70, 185, 78, 177, 86, 169, 94, 161, 102, 153, 110, 145, 118, 137, 126, 129 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q192[192] { + 0, 255, 4, 251, 8, 247, 12, 243, 16, 239, 20, 235, 24, 231, 28, 227, + 32, 223, 36, 219, 40, 215, 44, 211, 48, 207, 52, 203, 56, 199, 60, 195, + 64, 191, 68, 187, 72, 183, 76, 179, 80, 175, 84, 171, 88, 167, 92, 163, + 96, 159, 100, 155, 104, 151, 108, 147, 112, 143, 116, 139, 120, 135, 124, 131, + 1, 254, 5, 250, 9, 246, 13, 242, 17, 238, 21, 234, 25, 230, 29, 226, + 33, 222, 37, 218, 41, 214, 45, 210, 49, 206, 53, 202, 57, 198, 61, 194, + 65, 190, 69, 186, 73, 182, 77, 178, 81, 174, 85, 170, 89, 166, 93, 162, + 97, 158, 101, 154, 105, 150, 109, 146, 113, 142, 117, 138, 121, 134, 125, 130, + 2, 253, 6, 249, 10, 245, 14, 241, 18, 237, 22, 233, 26, 229, 30, 225, + 34, 221, 38, 217, 42, 213, 46, 209, 50, 205, 54, 201, 58, 197, 62, 193, + 66, 189, 70, 185, 74, 181, 78, 177, 82, 173, 86, 169, 90, 165, 94, 161, + 98, 157, 102, 153, 106, 149, 110, 145, 114, 141, 118, 137, 122, 133, 126, 129 +}; + +static const uint8_t color_scrambled_pquant_to_uquant_q256[256] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + +const uint8_t* color_scrambled_pquant_to_uquant_tables[17] { + color_scrambled_pquant_to_uquant_q6, + color_scrambled_pquant_to_uquant_q8, + color_scrambled_pquant_to_uquant_q10, + color_scrambled_pquant_to_uquant_q12, + color_scrambled_pquant_to_uquant_q16, + color_scrambled_pquant_to_uquant_q20, + color_scrambled_pquant_to_uquant_q24, + color_scrambled_pquant_to_uquant_q32, + color_scrambled_pquant_to_uquant_q40, + color_scrambled_pquant_to_uquant_q48, + color_scrambled_pquant_to_uquant_q64, + color_scrambled_pquant_to_uquant_q80, + color_scrambled_pquant_to_uquant_q96, + color_scrambled_pquant_to_uquant_q128, + color_scrambled_pquant_to_uquant_q160, + color_scrambled_pquant_to_uquant_q192, + color_scrambled_pquant_to_uquant_q256 +}; + +// The quant_mode_table[integer_count/2][bits] gives us the quantization level for a given integer +// count and number of bits that the integer may fit into. +const int8_t quant_mode_table[10][128] { + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + { + -1, -1, 0, 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, 0, 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, + 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, + 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, + 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, + 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }, + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19 + }, + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 17, 17 + } +}; diff --git a/thirdparty/astcenc/astcenc_symbolic_physical.cpp b/thirdparty/astcenc/astcenc_symbolic_physical.cpp new file mode 100644 index 0000000000..80221a6013 --- /dev/null +++ b/thirdparty/astcenc/astcenc_symbolic_physical.cpp @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Functions for converting between symbolic and physical encodings. + */ + +#include "astcenc_internal.h" + +#include <cassert> + +/** + * @brief Write up to 8 bits at an arbitrary bit offset. + * + * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so + * may span two separate bytes in memory. + * + * @param value The value to write. + * @param bitcount The number of bits to write, starting from LSB. + * @param bitoffset The bit offset to store at, between 0 and 7. + * @param[in,out] ptr The data pointer to write to. + */ +static inline void write_bits( + int value, + int bitcount, + int bitoffset, + uint8_t* ptr +) { + int mask = (1 << bitcount) - 1; + value &= mask; + ptr += bitoffset >> 3; + bitoffset &= 7; + value <<= bitoffset; + mask <<= bitoffset; + mask = ~mask; + + ptr[0] &= mask; + ptr[0] |= value; + ptr[1] &= mask >> 8; + ptr[1] |= value >> 8; +} + +/** + * @brief Read up to 8 bits at an arbitrary bit offset. + * + * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may + * span two separate bytes in memory. + * + * @param bitcount The number of bits to read. + * @param bitoffset The bit offset to read from, between 0 and 7. + * @param[in,out] ptr The data pointer to read from. + * + * @return The read value. + */ +static inline int read_bits( + int bitcount, + int bitoffset, + const uint8_t* ptr +) { + int mask = (1 << bitcount) - 1; + ptr += bitoffset >> 3; + bitoffset &= 7; + int value = ptr[0] | (ptr[1] << 8); + value >>= bitoffset; + value &= mask; + return value; +} + +/** + * @brief Reverse bits in a byte. + * + * @param p The value to reverse. + * + * @return The reversed result. + */ +static inline int bitrev8(int p) +{ + p = ((p & 0x0F) << 4) | ((p >> 4) & 0x0F); + p = ((p & 0x33) << 2) | ((p >> 2) & 0x33); + p = ((p & 0x55) << 1) | ((p >> 1) & 0x55); + return p; +} + +/* See header for documentation. */ +void symbolic_to_physical( + const block_size_descriptor& bsd, + const symbolic_compressed_block& scb, + physical_compressed_block& pcb +) { + assert(scb.block_type != SYM_BTYPE_ERROR); + + // Constant color block using UNORM16 colors + if (scb.block_type == SYM_BTYPE_CONST_U16) + { + // There is currently no attempt to coalesce larger void-extents + static const uint8_t cbytes[8] { 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + for (unsigned int i = 0; i < 8; i++) + { + pcb.data[i] = cbytes[i]; + } + + for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++) + { + pcb.data[2 * i + 8] = scb.constant_color[i] & 0xFF; + pcb.data[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF; + } + + return; + } + + // Constant color block using FP16 colors + if (scb.block_type == SYM_BTYPE_CONST_F16) + { + // There is currently no attempt to coalesce larger void-extents + static const uint8_t cbytes[8] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + for (unsigned int i = 0; i < 8; i++) + { + pcb.data[i] = cbytes[i]; + } + + for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++) + { + pcb.data[2 * i + 8] = scb.constant_color[i] & 0xFF; + pcb.data[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF; + } + + return; + } + + unsigned int partition_count = scb.partition_count; + + // Compress the weights. + // They are encoded as an ordinary integer-sequence, then bit-reversed + uint8_t weightbuf[16] { 0 }; + + const auto& bm = bsd.get_block_mode(scb.block_mode); + const auto& di = bsd.get_decimation_info(bm.decimation_mode); + int weight_count = di.weight_count; + quant_method weight_quant_method = bm.get_weight_quant_mode(); + float weight_quant_levels = static_cast<float>(get_quant_level(weight_quant_method)); + int is_dual_plane = bm.is_dual_plane; + + const auto& qat = quant_and_xfer_tables[weight_quant_method]; + + int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count; + + int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method); + + uint8_t weights[64]; + if (is_dual_plane) + { + for (int i = 0; i < weight_count; i++) + { + float uqw = static_cast<float>(scb.weights[i]); + float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f); + int qwi = static_cast<int>(qw + 0.5f); + weights[2 * i] = qat.scramble_map[qwi]; + + uqw = static_cast<float>(scb.weights[i + WEIGHTS_PLANE2_OFFSET]); + qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f); + qwi = static_cast<int>(qw + 0.5f); + weights[2 * i + 1] = qat.scramble_map[qwi]; + } + } + else + { + for (int i = 0; i < weight_count; i++) + { + float uqw = static_cast<float>(scb.weights[i]); + float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f); + int qwi = static_cast<int>(qw + 0.5f); + weights[i] = qat.scramble_map[qwi]; + } + } + + encode_ise(weight_quant_method, real_weight_count, weights, weightbuf, 0); + + for (int i = 0; i < 16; i++) + { + pcb.data[i] = static_cast<uint8_t>(bitrev8(weightbuf[15 - i])); + } + + write_bits(scb.block_mode, 11, 0, pcb.data); + write_bits(partition_count - 1, 2, 11, pcb.data); + + int below_weights_pos = 128 - bits_for_weights; + + // Encode partition index and color endpoint types for blocks with 2+ partitions + if (partition_count > 1) + { + write_bits(scb.partition_index, 6, 13, pcb.data); + write_bits(scb.partition_index >> 6, PARTITION_INDEX_BITS - 6, 19, pcb.data); + + if (scb.color_formats_matched) + { + write_bits(scb.color_formats[0] << 2, 6, 13 + PARTITION_INDEX_BITS, pcb.data); + } + else + { + // Check endpoint types for each partition to determine the lowest class present + int low_class = 4; + + for (unsigned int i = 0; i < partition_count; i++) + { + int class_of_format = scb.color_formats[i] >> 2; + low_class = astc::min(class_of_format, low_class); + } + + if (low_class == 3) + { + low_class = 2; + } + + int encoded_type = low_class + 1; + int bitpos = 2; + + for (unsigned int i = 0; i < partition_count; i++) + { + int classbit_of_format = (scb.color_formats[i] >> 2) - low_class; + encoded_type |= classbit_of_format << bitpos; + bitpos++; + } + + for (unsigned int i = 0; i < partition_count; i++) + { + int lowbits_of_format = scb.color_formats[i] & 3; + encoded_type |= lowbits_of_format << bitpos; + bitpos += 2; + } + + int encoded_type_lowpart = encoded_type & 0x3F; + int encoded_type_highpart = encoded_type >> 6; + int encoded_type_highpart_size = (3 * partition_count) - 4; + int encoded_type_highpart_pos = 128 - bits_for_weights - encoded_type_highpart_size; + write_bits(encoded_type_lowpart, 6, 13 + PARTITION_INDEX_BITS, pcb.data); + write_bits(encoded_type_highpart, encoded_type_highpart_size, encoded_type_highpart_pos, pcb.data); + below_weights_pos -= encoded_type_highpart_size; + } + } + else + { + write_bits(scb.color_formats[0], 4, 13, pcb.data); + } + + // In dual-plane mode, encode the color component of the second plane of weights + if (is_dual_plane) + { + write_bits(scb.plane2_component, 2, below_weights_pos - 2, pcb.data); + } + + // Encode the color components + uint8_t values_to_encode[32]; + int valuecount_to_encode = 0; + + const uint8_t* pack_table = color_uquant_to_scrambled_pquant_tables[scb.quant_mode - QUANT_6]; + for (unsigned int i = 0; i < scb.partition_count; i++) + { + int vals = 2 * (scb.color_formats[i] >> 2) + 2; + assert(vals <= 8); + for (int j = 0; j < vals; j++) + { + values_to_encode[j + valuecount_to_encode] = pack_table[scb.color_values[i][j]]; + } + valuecount_to_encode += vals; + } + + encode_ise(scb.get_color_quant_mode(), valuecount_to_encode, values_to_encode, pcb.data, + scb.partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS); +} + +/* See header for documentation. */ +void physical_to_symbolic( + const block_size_descriptor& bsd, + const physical_compressed_block& pcb, + symbolic_compressed_block& scb +) { + uint8_t bswapped[16]; + + scb.block_type = SYM_BTYPE_NONCONST; + + // Extract header fields + int block_mode = read_bits(11, 0, pcb.data); + if ((block_mode & 0x1FF) == 0x1FC) + { + // Constant color block + + // Check what format the data has + if (block_mode & 0x200) + { + scb.block_type = SYM_BTYPE_CONST_F16; + } + else + { + scb.block_type = SYM_BTYPE_CONST_U16; + } + + scb.partition_count = 0; + for (int i = 0; i < 4; i++) + { + scb.constant_color[i] = pcb.data[2 * i + 8] | (pcb.data[2 * i + 9] << 8); + } + + // Additionally, check that the void-extent + if (bsd.zdim == 1) + { + // 2D void-extent + int rsvbits = read_bits(2, 10, pcb.data); + if (rsvbits != 3) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + + int vx_low_s = read_bits(8, 12, pcb.data) | (read_bits(5, 12 + 8, pcb.data) << 8); + int vx_high_s = read_bits(8, 25, pcb.data) | (read_bits(5, 25 + 8, pcb.data) << 8); + int vx_low_t = read_bits(8, 38, pcb.data) | (read_bits(5, 38 + 8, pcb.data) << 8); + int vx_high_t = read_bits(8, 51, pcb.data) | (read_bits(5, 51 + 8, pcb.data) << 8); + + int all_ones = vx_low_s == 0x1FFF && vx_high_s == 0x1FFF && vx_low_t == 0x1FFF && vx_high_t == 0x1FFF; + + if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t) && !all_ones) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + } + else + { + // 3D void-extent + int vx_low_s = read_bits(9, 10, pcb.data); + int vx_high_s = read_bits(9, 19, pcb.data); + int vx_low_t = read_bits(9, 28, pcb.data); + int vx_high_t = read_bits(9, 37, pcb.data); + int vx_low_p = read_bits(9, 46, pcb.data); + int vx_high_p = read_bits(9, 55, pcb.data); + + int all_ones = vx_low_s == 0x1FF && vx_high_s == 0x1FF && vx_low_t == 0x1FF && vx_high_t == 0x1FF && vx_low_p == 0x1FF && vx_high_p == 0x1FF; + + if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t || vx_low_p >= vx_high_p) && !all_ones) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + } + + return; + } + + unsigned int packed_index = bsd.block_mode_packed_index[block_mode]; + if (packed_index == BLOCK_BAD_BLOCK_MODE) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + + const auto& bm = bsd.get_block_mode(block_mode); + const auto& di = bsd.get_decimation_info(bm.decimation_mode); + + int weight_count = di.weight_count; + promise(weight_count > 0); + + quant_method weight_quant_method = static_cast<quant_method>(bm.quant_mode); + int is_dual_plane = bm.is_dual_plane; + + int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count; + + int partition_count = read_bits(2, 11, pcb.data) + 1; + promise(partition_count > 0); + + scb.block_mode = static_cast<uint16_t>(block_mode); + scb.partition_count = static_cast<uint8_t>(partition_count); + + for (int i = 0; i < 16; i++) + { + bswapped[i] = static_cast<uint8_t>(bitrev8(pcb.data[15 - i])); + } + + int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method); + + int below_weights_pos = 128 - bits_for_weights; + + uint8_t indices[64]; + const auto& qat = quant_and_xfer_tables[weight_quant_method]; + + decode_ise(weight_quant_method, real_weight_count, bswapped, indices, 0); + + if (is_dual_plane) + { + for (int i = 0; i < weight_count; i++) + { + scb.weights[i] = qat.unscramble_and_unquant_map[indices[2 * i]]; + scb.weights[i + WEIGHTS_PLANE2_OFFSET] = qat.unscramble_and_unquant_map[indices[2 * i + 1]]; + } + } + else + { + for (int i = 0; i < weight_count; i++) + { + scb.weights[i] = qat.unscramble_and_unquant_map[indices[i]]; + } + } + + if (is_dual_plane && partition_count == 4) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + + scb.color_formats_matched = 0; + + // Determine the format of each endpoint pair + int color_formats[BLOCK_MAX_PARTITIONS]; + int encoded_type_highpart_size = 0; + if (partition_count == 1) + { + color_formats[0] = read_bits(4, 13, pcb.data); + scb.partition_index = 0; + } + else + { + encoded_type_highpart_size = (3 * partition_count) - 4; + below_weights_pos -= encoded_type_highpart_size; + int encoded_type = read_bits(6, 13 + PARTITION_INDEX_BITS, pcb.data) | (read_bits(encoded_type_highpart_size, below_weights_pos, pcb.data) << 6); + int baseclass = encoded_type & 0x3; + if (baseclass == 0) + { + for (int i = 0; i < partition_count; i++) + { + color_formats[i] = (encoded_type >> 2) & 0xF; + } + + below_weights_pos += encoded_type_highpart_size; + scb.color_formats_matched = 1; + encoded_type_highpart_size = 0; + } + else + { + int bitpos = 2; + baseclass--; + + for (int i = 0; i < partition_count; i++) + { + color_formats[i] = (((encoded_type >> bitpos) & 1) + baseclass) << 2; + bitpos++; + } + + for (int i = 0; i < partition_count; i++) + { + color_formats[i] |= (encoded_type >> bitpos) & 3; + bitpos += 2; + } + } + scb.partition_index = static_cast<uint16_t>(read_bits(6, 13, pcb.data) | (read_bits(PARTITION_INDEX_BITS - 6, 19, pcb.data) << 6)); + } + + for (int i = 0; i < partition_count; i++) + { + scb.color_formats[i] = static_cast<uint8_t>(color_formats[i]); + } + + // Determine number of color endpoint integers + int color_integer_count = 0; + for (int i = 0; i < partition_count; i++) + { + int endpoint_class = color_formats[i] >> 2; + color_integer_count += (endpoint_class + 1) * 2; + } + + if (color_integer_count > 18) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + + // Determine the color endpoint format to use + static const int color_bits_arr[5] { -1, 115 - 4, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS }; + int color_bits = color_bits_arr[partition_count] - bits_for_weights - encoded_type_highpart_size; + if (is_dual_plane) + { + color_bits -= 2; + } + + if (color_bits < 0) + { + color_bits = 0; + } + + int color_quant_level = quant_mode_table[color_integer_count >> 1][color_bits]; + if (color_quant_level < QUANT_6) + { + scb.block_type = SYM_BTYPE_ERROR; + return; + } + + // Unpack the integer color values and assign to endpoints + scb.quant_mode = static_cast<quant_method>(color_quant_level); + + uint8_t values_to_decode[32]; + decode_ise(static_cast<quant_method>(color_quant_level), color_integer_count, pcb.data, + values_to_decode, (partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS)); + + int valuecount_to_decode = 0; + const uint8_t* unpack_table = color_scrambled_pquant_to_uquant_tables[scb.quant_mode - QUANT_6]; + for (int i = 0; i < partition_count; i++) + { + int vals = 2 * (color_formats[i] >> 2) + 2; + for (int j = 0; j < vals; j++) + { + scb.color_values[i][j] = unpack_table[values_to_decode[j + valuecount_to_decode]]; + } + valuecount_to_decode += vals; + } + + // Fetch component for second-plane in the case of dual plane of weights. + scb.plane2_component = -1; + if (is_dual_plane) + { + scb.plane2_component = static_cast<int8_t>(read_bits(2, below_weights_pos - 2, pcb.data)); + } +} diff --git a/thirdparty/astcenc/astcenc_vecmathlib.h b/thirdparty/astcenc/astcenc_vecmathlib.h new file mode 100644 index 0000000000..d48f1d73ea --- /dev/null +++ b/thirdparty/astcenc/astcenc_vecmathlib.h @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2019-2022 Arm Limited +// Copyright 2008 Jose Fonseca +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/* + * This module implements vector support for floats, ints, and vector lane + * control masks. It provides access to both explicit vector width types, and + * flexible N-wide types where N can be determined at compile time. + * + * The design of this module encourages use of vector length agnostic code, via + * the vint, vfloat, and vmask types. These will take on the widest SIMD vector + * with that is available at compile time. The current vector width is + * accessible for e.g. loop strides via the ASTCENC_SIMD_WIDTH constant. + * + * Explicit scalar types are accessible via the vint1, vfloat1, vmask1 types. + * These are provided primarily for prototyping and algorithm debug of VLA + * implementations. + * + * Explicit 4-wide types are accessible via the vint4, vfloat4, and vmask4 + * types. These are provided for use by VLA code, but are also expected to be + * used as a fixed-width type and will supported a reference C++ fallback for + * use on platforms without SIMD intrinsics. + * + * Explicit 8-wide types are accessible via the vint8, vfloat8, and vmask8 + * types. These are provide for use by VLA code, and are not expected to be + * used as a fixed-width type in normal code. No reference C implementation is + * provided on platforms without underlying SIMD intrinsics. + * + * With the current implementation ISA support is provided for: + * + * * 1-wide for scalar reference. + * * 4-wide for Armv8-A NEON. + * * 4-wide for x86-64 SSE2. + * * 4-wide for x86-64 SSE4.1. + * * 8-wide for x86-64 AVX2. + */ + +#ifndef ASTC_VECMATHLIB_H_INCLUDED +#define ASTC_VECMATHLIB_H_INCLUDED + +#if ASTCENC_SSE != 0 || ASTCENC_AVX != 0 + #include <immintrin.h> +#elif ASTCENC_NEON != 0 + #include <arm_neon.h> +#endif + +#if !defined(__clang__) && defined(_MSC_VER) + #define ASTCENC_SIMD_INLINE __forceinline + #define ASTCENC_NO_INLINE +#elif defined(__GNUC__) && !defined(__clang__) + #define ASTCENC_SIMD_INLINE __attribute__((always_inline)) inline + #define ASTCENC_NO_INLINE __attribute__ ((noinline)) +#else + #define ASTCENC_SIMD_INLINE __attribute__((always_inline, nodebug)) inline + #define ASTCENC_NO_INLINE __attribute__ ((noinline)) +#endif + +#if ASTCENC_AVX >= 2 + /* If we have AVX2 expose 8-wide VLA. */ + #include "astcenc_vecmathlib_sse_4.h" + #include "astcenc_vecmathlib_common_4.h" + #include "astcenc_vecmathlib_avx2_8.h" + + #define ASTCENC_SIMD_WIDTH 8 + + using vfloat = vfloat8; + + #if defined(ASTCENC_NO_INVARIANCE) + using vfloatacc = vfloat8; + #else + using vfloatacc = vfloat4; + #endif + + using vint = vint8; + using vmask = vmask8; + + constexpr auto loada = vfloat8::loada; + constexpr auto load1 = vfloat8::load1; + +#elif ASTCENC_SSE >= 20 + /* If we have SSE expose 4-wide VLA, and 4-wide fixed width. */ + #include "astcenc_vecmathlib_sse_4.h" + #include "astcenc_vecmathlib_common_4.h" + + #define ASTCENC_SIMD_WIDTH 4 + + using vfloat = vfloat4; + using vfloatacc = vfloat4; + using vint = vint4; + using vmask = vmask4; + + constexpr auto loada = vfloat4::loada; + constexpr auto load1 = vfloat4::load1; + +#elif ASTCENC_NEON > 0 + /* If we have NEON expose 4-wide VLA. */ + #include "astcenc_vecmathlib_neon_4.h" + #include "astcenc_vecmathlib_common_4.h" + + #define ASTCENC_SIMD_WIDTH 4 + + using vfloat = vfloat4; + using vfloatacc = vfloat4; + using vint = vint4; + using vmask = vmask4; + + constexpr auto loada = vfloat4::loada; + constexpr auto load1 = vfloat4::load1; + +#else + // If we have nothing expose 4-wide VLA, and 4-wide fixed width. + + // Note: We no longer expose the 1-wide scalar fallback because it is not + // invariant with the 4-wide path due to algorithms that use horizontal + // operations that accumulate a local vector sum before accumulating into + // a running sum. + // + // For 4 items adding into an accumulator using 1-wide vectors the sum is: + // + // result = ((((sum + l0) + l1) + l2) + l3) + // + // ... whereas the accumulator for a 4-wide vector sum is: + // + // result = sum + ((l0 + l2) + (l1 + l3)) + // + // In "normal maths" this is the same, but the floating point reassociation + // differences mean that these will not produce the same result. + + #include "astcenc_vecmathlib_none_4.h" + #include "astcenc_vecmathlib_common_4.h" + + #define ASTCENC_SIMD_WIDTH 4 + + using vfloat = vfloat4; + using vfloatacc = vfloat4; + using vint = vint4; + using vmask = vmask4; + + constexpr auto loada = vfloat4::loada; + constexpr auto load1 = vfloat4::load1; +#endif + +/** + * @brief Round a count down to the largest multiple of 8. + * + * @param count The unrounded value. + * + * @return The rounded value. + */ +ASTCENC_SIMD_INLINE unsigned int round_down_to_simd_multiple_8(unsigned int count) +{ + return count & static_cast<unsigned int>(~(8 - 1)); +} + +/** + * @brief Round a count down to the largest multiple of 4. + * + * @param count The unrounded value. + * + * @return The rounded value. + */ +ASTCENC_SIMD_INLINE unsigned int round_down_to_simd_multiple_4(unsigned int count) +{ + return count & static_cast<unsigned int>(~(4 - 1)); +} + +/** + * @brief Round a count down to the largest multiple of the SIMD width. + * + * Assumption that the vector width is a power of two ... + * + * @param count The unrounded value. + * + * @return The rounded value. + */ +ASTCENC_SIMD_INLINE unsigned int round_down_to_simd_multiple_vla(unsigned int count) +{ + return count & static_cast<unsigned int>(~(ASTCENC_SIMD_WIDTH - 1)); +} + +/** + * @brief Round a count up to the largest multiple of the SIMD width. + * + * Assumption that the vector width is a power of two ... + * + * @param count The unrounded value. + * + * @return The rounded value. + */ +ASTCENC_SIMD_INLINE unsigned int round_up_to_simd_multiple_vla(unsigned int count) +{ + unsigned int multiples = (count + ASTCENC_SIMD_WIDTH - 1) / ASTCENC_SIMD_WIDTH; + return multiples * ASTCENC_SIMD_WIDTH; +} + +/** + * @brief Return @c a with lanes negated if the @c b lane is negative. + */ +ASTCENC_SIMD_INLINE vfloat change_sign(vfloat a, vfloat b) +{ + vint ia = float_as_int(a); + vint ib = float_as_int(b); + vint sign_mask(static_cast<int>(0x80000000)); + vint r = ia ^ (ib & sign_mask); + return int_as_float(r); +} + +/** + * @brief Return fast, but approximate, vector atan(x). + * + * Max error of this implementation is 0.004883. + */ +ASTCENC_SIMD_INLINE vfloat atan(vfloat x) +{ + vmask c = abs(x) > vfloat(1.0f); + vfloat z = change_sign(vfloat(astc::PI_OVER_TWO), x); + vfloat y = select(x, vfloat(1.0f) / x, c); + y = y / (y * y * vfloat(0.28f) + vfloat(1.0f)); + return select(y, z - y, c); +} + +/** + * @brief Return fast, but approximate, vector atan2(x, y). + */ +ASTCENC_SIMD_INLINE vfloat atan2(vfloat y, vfloat x) +{ + vfloat z = atan(abs(y / x)); + vmask xmask = vmask(float_as_int(x).m); + return change_sign(select_msb(z, vfloat(astc::PI) - z, xmask), y); +} + +/* + * @brief Factory that returns a unit length 4 component vfloat4. + */ +static ASTCENC_SIMD_INLINE vfloat4 unit4() +{ + return vfloat4(0.5f); +} + +/** + * @brief Factory that returns a unit length 3 component vfloat4. + */ +static ASTCENC_SIMD_INLINE vfloat4 unit3() +{ + float val = 0.577350258827209473f; + return vfloat4(val, val, val, 0.0f); +} + +/** + * @brief Factory that returns a unit length 2 component vfloat4. + */ +static ASTCENC_SIMD_INLINE vfloat4 unit2() +{ + float val = 0.707106769084930420f; + return vfloat4(val, val, 0.0f, 0.0f); +} + +/** + * @brief Factory that returns a 3 component vfloat4. + */ +static ASTCENC_SIMD_INLINE vfloat4 vfloat3(float a, float b, float c) +{ + return vfloat4(a, b, c, 0.0f); +} + +/** + * @brief Factory that returns a 2 component vfloat4. + */ +static ASTCENC_SIMD_INLINE vfloat4 vfloat2(float a, float b) +{ + return vfloat4(a, b, 0.0f, 0.0f); +} + +/** + * @brief Normalize a non-zero length vector to unit length. + */ +static ASTCENC_SIMD_INLINE vfloat4 normalize(vfloat4 a) +{ + vfloat4 length = dot(a, a); + return a / sqrt(length); +} + +/** + * @brief Normalize a vector, returning @c safe if len is zero. + */ +static ASTCENC_SIMD_INLINE vfloat4 normalize_safe(vfloat4 a, vfloat4 safe) +{ + vfloat4 length = dot(a, a); + if (length.lane<0>() != 0.0f) + { + return a / sqrt(length); + } + + return safe; +} + + + +#define POLY0(x, c0) ( c0) +#define POLY1(x, c0, c1) ((POLY0(x, c1) * x) + c0) +#define POLY2(x, c0, c1, c2) ((POLY1(x, c1, c2) * x) + c0) +#define POLY3(x, c0, c1, c2, c3) ((POLY2(x, c1, c2, c3) * x) + c0) +#define POLY4(x, c0, c1, c2, c3, c4) ((POLY3(x, c1, c2, c3, c4) * x) + c0) +#define POLY5(x, c0, c1, c2, c3, c4, c5) ((POLY4(x, c1, c2, c3, c4, c5) * x) + c0) + +/** + * @brief Compute an approximate exp2(x) for each lane in the vector. + * + * Based on 5th degree minimax polynomials, ported from this blog + * https://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html + */ +static ASTCENC_SIMD_INLINE vfloat4 exp2(vfloat4 x) +{ + x = clamp(-126.99999f, 129.0f, x); + + vint4 ipart = float_to_int(x - 0.5f); + vfloat4 fpart = x - int_to_float(ipart); + + // Integer contrib, using 1 << ipart + vfloat4 iexp = int_as_float(lsl<23>(ipart + 127)); + + // Fractional contrib, using polynomial fit of 2^x in range [-0.5, 0.5) + vfloat4 fexp = POLY5(fpart, + 9.9999994e-1f, + 6.9315308e-1f, + 2.4015361e-1f, + 5.5826318e-2f, + 8.9893397e-3f, + 1.8775767e-3f); + + return iexp * fexp; +} + +/** + * @brief Compute an approximate log2(x) for each lane in the vector. + * + * Based on 5th degree minimax polynomials, ported from this blog + * https://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html + */ +static ASTCENC_SIMD_INLINE vfloat4 log2(vfloat4 x) +{ + vint4 exp(0x7F800000); + vint4 mant(0x007FFFFF); + vint4 one(0x3F800000); + + vint4 i = float_as_int(x); + + vfloat4 e = int_to_float(lsr<23>(i & exp) - 127); + + vfloat4 m = int_as_float((i & mant) | one); + + // Polynomial fit of log2(x)/(x - 1), for x in range [1, 2) + vfloat4 p = POLY4(m, + 2.8882704548164776201f, + -2.52074962577807006663f, + 1.48116647521213171641f, + -0.465725644288844778798f, + 0.0596515482674574969533f); + + // Increases the polynomial degree, but ensures that log2(1) == 0 + p = p * (m - 1.0f); + + return p + e; +} + +/** + * @brief Compute an approximate pow(x, y) for each lane in the vector. + * + * Power function based on the exp2(log2(x) * y) transform. + */ +static ASTCENC_SIMD_INLINE vfloat4 pow(vfloat4 x, vfloat4 y) +{ + vmask4 zero_mask = y == vfloat4(0.0f); + vfloat4 estimate = exp2(log2(x) * y); + + // Guarantee that y == 0 returns exactly 1.0f + return select(estimate, vfloat4(1.0f), zero_mask); +} + +/** + * @brief Count the leading zeros for each lane in @c a. + * + * Valid for all data values of @c a; will return a per-lane value [0, 32]. + */ +static ASTCENC_SIMD_INLINE vint4 clz(vint4 a) +{ + // This function is a horrible abuse of floating point exponents to convert + // the original integer value into a 2^N encoding we can recover easily. + + // Convert to float without risk of rounding up by keeping only top 8 bits. + // This trick is is guaranteed to keep top 8 bits and clear the 9th. + a = (~lsr<8>(a)) & a; + a = float_as_int(int_to_float(a)); + + // Extract and unbias exponent + a = vint4(127 + 31) - lsr<23>(a); + + // Clamp result to a valid 32-bit range + return clamp(0, 32, a); +} + +/** + * @brief Return lanewise 2^a for each lane in @c a. + * + * Use of signed int means that this is only valid for values in range [0, 31]. + */ +static ASTCENC_SIMD_INLINE vint4 two_to_the_n(vint4 a) +{ + // 2^30 is the largest signed number than can be represented + assert(all(a < vint4(31))); + + // This function is a horrible abuse of floating point to use the exponent + // and float conversion to generate a 2^N multiple. + + // Bias the exponent + vint4 exp = a + 127; + exp = lsl<23>(exp); + + // Reinterpret the bits as a float, and then convert to an int + vfloat4 f = int_as_float(exp); + return float_to_int(f); +} + +/** + * @brief Convert unorm16 [0, 65535] to float16 in range [0, 1]. + */ +static ASTCENC_SIMD_INLINE vint4 unorm16_to_sf16(vint4 p) +{ + vint4 fp16_one = vint4(0x3C00); + vint4 fp16_small = lsl<8>(p); + + vmask4 is_one = p == vint4(0xFFFF); + vmask4 is_small = p < vint4(4); + + // Manually inline clz() on Visual Studio to avoid release build codegen bug + // see https://github.com/ARM-software/astc-encoder/issues/259 +#if !defined(__clang__) && defined(_MSC_VER) + vint4 a = (~lsr<8>(p)) & p; + a = float_as_int(int_to_float(a)); + a = vint4(127 + 31) - lsr<23>(a); + vint4 lz = clamp(0, 32, a) - 16; +#else + vint4 lz = clz(p) - 16; +#endif + + p = p * two_to_the_n(lz + 1); + p = p & vint4(0xFFFF); + + p = lsr<6>(p); + + p = p | lsl<10>(vint4(14) - lz); + + vint4 r = select(p, fp16_one, is_one); + r = select(r, fp16_small, is_small); + return r; +} + +/** + * @brief Convert 16-bit LNS to float16. + */ +static ASTCENC_SIMD_INLINE vint4 lns_to_sf16(vint4 p) +{ + vint4 mc = p & 0x7FF; + vint4 ec = lsr<11>(p); + + vint4 mc_512 = mc * 3; + vmask4 mask_512 = mc < vint4(512); + + vint4 mc_1536 = mc * 4 - 512; + vmask4 mask_1536 = mc < vint4(1536); + + vint4 mc_else = mc * 5 - 2048; + + vint4 mt = mc_else; + mt = select(mt, mc_1536, mask_1536); + mt = select(mt, mc_512, mask_512); + + vint4 res = lsl<10>(ec) | lsr<3>(mt); + return min(res, vint4(0x7BFF)); +} + +/** + * @brief Extract mantissa and exponent of a float value. + * + * @param a The input value. + * @param[out] exp The output exponent. + * + * @return The mantissa. + */ +static ASTCENC_SIMD_INLINE vfloat4 frexp(vfloat4 a, vint4& exp) +{ + // Interpret the bits as an integer + vint4 ai = float_as_int(a); + + // Extract and unbias the exponent + exp = (lsr<23>(ai) & 0xFF) - 126; + + // Extract and unbias the mantissa + vint4 manti = (ai & static_cast<int>(0x807FFFFF)) | 0x3F000000; + return int_as_float(manti); +} + +/** + * @brief Convert float to 16-bit LNS. + */ +static ASTCENC_SIMD_INLINE vfloat4 float_to_lns(vfloat4 a) +{ + vint4 exp; + vfloat4 mant = frexp(a, exp); + + // Do these early before we start messing about ... + vmask4 mask_underflow_nan = ~(a > vfloat4(1.0f / 67108864.0f)); + vmask4 mask_infinity = a >= vfloat4(65536.0f); + + // If input is smaller than 2^-14, multiply by 2^25 and don't bias. + vmask4 exp_lt_m13 = exp < vint4(-13); + + vfloat4 a1a = a * 33554432.0f; + vint4 expa = vint4::zero(); + + vfloat4 a1b = (mant - 0.5f) * 4096; + vint4 expb = exp + 14; + + a = select(a1b, a1a, exp_lt_m13); + exp = select(expb, expa, exp_lt_m13); + + vmask4 a_lt_384 = a < vfloat4(384.0f); + vmask4 a_lt_1408 = a <= vfloat4(1408.0f); + + vfloat4 a2a = a * (4.0f / 3.0f); + vfloat4 a2b = a + 128.0f; + vfloat4 a2c = (a + 512.0f) * (4.0f / 5.0f); + + a = a2c; + a = select(a, a2b, a_lt_1408); + a = select(a, a2a, a_lt_384); + + a = a + (int_to_float(exp) * 2048.0f) + 1.0f; + + a = select(a, vfloat4(65535.0f), mask_infinity); + a = select(a, vfloat4::zero(), mask_underflow_nan); + + return a; +} + +namespace astc +{ + +static ASTCENC_SIMD_INLINE float pow(float x, float y) +{ + return pow(vfloat4(x), vfloat4(y)).lane<0>(); +} + +} + +#endif // #ifndef ASTC_VECMATHLIB_H_INCLUDED diff --git a/thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h b/thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h new file mode 100644 index 0000000000..a785aca75b --- /dev/null +++ b/thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h @@ -0,0 +1,1204 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2019-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief 8x32-bit vectors, implemented using AVX2. + * + * This module implements 8-wide 32-bit float, int, and mask vectors for x86 + * AVX2. + * + * There is a baseline level of functionality provided by all vector widths and + * implementations. This is implemented using identical function signatures, + * modulo data type, so we can use them as substitutable implementations in VLA + * code. + */ + +#ifndef ASTC_VECMATHLIB_AVX2_8_H_INCLUDED +#define ASTC_VECMATHLIB_AVX2_8_H_INCLUDED + +#ifndef ASTCENC_SIMD_INLINE + #error "Include astcenc_vecmathlib.h, do not include directly" +#endif + +#include <cstdio> + +// Define convenience intrinsics that are missing on older compilers +#define astcenc_mm256_set_m128i(m, n) _mm256_insertf128_si256(_mm256_castsi128_si256((n)), (m), 1) + +// ============================================================================ +// vfloat8 data type +// ============================================================================ + +/** + * @brief Data type for 8-wide floats. + */ +struct vfloat8 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vfloat8() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using loada() which is better with vectors if data is aligned + * to vector length. + */ + ASTCENC_SIMD_INLINE explicit vfloat8(const float *p) + { + m = _mm256_loadu_ps(p); + } + + /** + * @brief Construct from 1 scalar value replicated across all lanes. + * + * Consider using zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vfloat8(float a) + { + m = _mm256_set1_ps(a); + } + + /** + * @brief Construct from 8 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat8( + float a, float b, float c, float d, + float e, float f, float g, float h) + { + m = _mm256_set_ps(h, g, f, e, d, c, b, a); + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat8(__m256 a) + { + m = a; + } + + /** + * @brief Get the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE float lane() const + { + #if !defined(__clang__) && defined(_MSC_VER) + return m.m256_f32[l]; + #else + union { __m256 m; float f[8]; } cvt; + cvt.m = m; + return cvt.f[l]; + #endif + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vfloat8 zero() + { + return vfloat8(_mm256_setzero_ps()); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vfloat8 load1(const float* p) + { + return vfloat8(_mm256_broadcast_ss(p)); + } + + /** + * @brief Factory that returns a vector loaded from 32B aligned memory. + */ + static ASTCENC_SIMD_INLINE vfloat8 loada(const float* p) + { + return vfloat8(_mm256_load_ps(p)); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vfloat8 lane_id() + { + return vfloat8(_mm256_set_ps(7, 6, 5, 4, 3, 2, 1, 0)); + } + + /** + * @brief The vector ... + */ + __m256 m; +}; + +// ============================================================================ +// vint8 data type +// ============================================================================ + +/** + * @brief Data type for 8-wide ints. + */ +struct vint8 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vint8() = default; + + /** + * @brief Construct from 8 values loaded from an unaligned address. + * + * Consider using loada() which is better with vectors if data is aligned + * to vector length. + */ + ASTCENC_SIMD_INLINE explicit vint8(const int *p) + { + m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(p)); + } + + /** + * @brief Construct from 8 uint8_t loaded from an unaligned address. + */ + ASTCENC_SIMD_INLINE explicit vint8(const uint8_t *p) + { + // _mm_loadu_si64 would be nicer syntax, but missing on older GCC + m = _mm256_cvtepu8_epi32(_mm_cvtsi64_si128(*reinterpret_cast<const long long*>(p))); + } + + /** + * @brief Construct from 1 scalar value replicated across all lanes. + * + * Consider using vfloat4::zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vint8(int a) + { + m = _mm256_set1_epi32(a); + } + + /** + * @brief Construct from 8 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint8( + int a, int b, int c, int d, + int e, int f, int g, int h) + { + m = _mm256_set_epi32(h, g, f, e, d, c, b, a); + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint8(__m256i a) + { + m = a; + } + + /** + * @brief Get the scalar from a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE int lane() const + { + #if !defined(__clang__) && defined(_MSC_VER) + return m.m256i_i32[l]; + #else + union { __m256i m; int f[8]; } cvt; + cvt.m = m; + return cvt.f[l]; + #endif + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vint8 zero() + { + return vint8(_mm256_setzero_si256()); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vint8 load1(const int* p) + { + __m128i a = _mm_set1_epi32(*p); + return vint8(_mm256_broadcastd_epi32(a)); + } + + /** + * @brief Factory that returns a vector loaded from 32B aligned memory. + */ + static ASTCENC_SIMD_INLINE vint8 loada(const int* p) + { + return vint8(_mm256_load_si256(reinterpret_cast<const __m256i*>(p))); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vint8 lane_id() + { + return vint8(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)); + } + + /** + * @brief The vector ... + */ + __m256i m; +}; + +// ============================================================================ +// vmask8 data type +// ============================================================================ + +/** + * @brief Data type for 8-wide control plane masks. + */ +struct vmask8 +{ + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask8(__m256 a) + { + m = a; + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask8(__m256i a) + { + m = _mm256_castsi256_ps(a); + } + + /** + * @brief Construct from 1 scalar value. + */ + ASTCENC_SIMD_INLINE explicit vmask8(bool a) + { + vint8 mask(a == false ? 0 : -1); + m = _mm256_castsi256_ps(mask.m); + } + + /** + * @brief The vector ... + */ + __m256 m; +}; + +// ============================================================================ +// vmask8 operators and functions +// ============================================================================ + +/** + * @brief Overload: mask union (or). + */ +ASTCENC_SIMD_INLINE vmask8 operator|(vmask8 a, vmask8 b) +{ + return vmask8(_mm256_or_ps(a.m, b.m)); +} + +/** + * @brief Overload: mask intersect (and). + */ +ASTCENC_SIMD_INLINE vmask8 operator&(vmask8 a, vmask8 b) +{ + return vmask8(_mm256_and_ps(a.m, b.m)); +} + +/** + * @brief Overload: mask difference (xor). + */ +ASTCENC_SIMD_INLINE vmask8 operator^(vmask8 a, vmask8 b) +{ + return vmask8(_mm256_xor_ps(a.m, b.m)); +} + +/** + * @brief Overload: mask invert (not). + */ +ASTCENC_SIMD_INLINE vmask8 operator~(vmask8 a) +{ + return vmask8(_mm256_xor_si256(_mm256_castps_si256(a.m), _mm256_set1_epi32(-1))); +} + +/** + * @brief Return a 8-bit mask code indicating mask status. + * + * bit0 = lane 0 + */ +ASTCENC_SIMD_INLINE unsigned int mask(vmask8 a) +{ + return static_cast<unsigned int>(_mm256_movemask_ps(a.m)); +} + +/** + * @brief True if any lanes are enabled, false otherwise. + */ +ASTCENC_SIMD_INLINE bool any(vmask8 a) +{ + return mask(a) != 0; +} + +/** + * @brief True if all lanes are enabled, false otherwise. + */ +ASTCENC_SIMD_INLINE bool all(vmask8 a) +{ + return mask(a) == 0xFF; +} + +// ============================================================================ +// vint8 operators and functions +// ============================================================================ +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vint8 operator+(vint8 a, vint8 b) +{ + return vint8(_mm256_add_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector incremental addition. + */ +ASTCENC_SIMD_INLINE vint8& operator+=(vint8& a, const vint8& b) +{ + a = a + b; + return a; +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vint8 operator-(vint8 a, vint8 b) +{ + return vint8(_mm256_sub_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vint8 operator*(vint8 a, vint8 b) +{ + return vint8(_mm256_mullo_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector bit invert. + */ +ASTCENC_SIMD_INLINE vint8 operator~(vint8 a) +{ + return vint8(_mm256_xor_si256(a.m, _mm256_set1_epi32(-1))); +} + +/** + * @brief Overload: vector by vector bitwise or. + */ +ASTCENC_SIMD_INLINE vint8 operator|(vint8 a, vint8 b) +{ + return vint8(_mm256_or_si256(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector bitwise and. + */ +ASTCENC_SIMD_INLINE vint8 operator&(vint8 a, vint8 b) +{ + return vint8(_mm256_and_si256(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector bitwise xor. + */ +ASTCENC_SIMD_INLINE vint8 operator^(vint8 a, vint8 b) +{ + return vint8(_mm256_xor_si256(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask8 operator==(vint8 a, vint8 b) +{ + return vmask8(_mm256_cmpeq_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask8 operator!=(vint8 a, vint8 b) +{ + return ~vmask8(_mm256_cmpeq_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask8 operator<(vint8 a, vint8 b) +{ + return vmask8(_mm256_cmpgt_epi32(b.m, a.m)); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask8 operator>(vint8 a, vint8 b) +{ + return vmask8(_mm256_cmpgt_epi32(a.m, b.m)); +} + +/** + * @brief Logical shift left. + */ +template <int s> ASTCENC_SIMD_INLINE vint8 lsl(vint8 a) +{ + return vint8(_mm256_slli_epi32(a.m, s)); +} + +/** + * @brief Arithmetic shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint8 asr(vint8 a) +{ + return vint8(_mm256_srai_epi32(a.m, s)); +} + +/** + * @brief Logical shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint8 lsr(vint8 a) +{ + return vint8(_mm256_srli_epi32(a.m, s)); +} + +/** + * @brief Return the min vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint8 min(vint8 a, vint8 b) +{ + return vint8(_mm256_min_epi32(a.m, b.m)); +} + +/** + * @brief Return the max vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint8 max(vint8 a, vint8 b) +{ + return vint8(_mm256_max_epi32(a.m, b.m)); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vint8 hmin(vint8 a) +{ + __m128i m = _mm_min_epi32(_mm256_extracti128_si256(a.m, 0), _mm256_extracti128_si256(a.m, 1)); + m = _mm_min_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,3,2))); + m = _mm_min_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,1))); + m = _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,0)); + + __m256i r = astcenc_mm256_set_m128i(m, m); + vint8 vmin(r); + return vmin; +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vint8 hmax(vint8 a) +{ + __m128i m = _mm_max_epi32(_mm256_extracti128_si256(a.m, 0), _mm256_extracti128_si256(a.m, 1)); + m = _mm_max_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,3,2))); + m = _mm_max_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,1))); + m = _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,0)); + + __m256i r = astcenc_mm256_set_m128i(m, m); + vint8 vmax(r); + return vmax; +} + +/** + * @brief Store a vector to a 16B aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vint8 a, int* p) +{ + _mm256_store_si256(reinterpret_cast<__m256i*>(p), a.m); +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vint8 a, int* p) +{ + _mm256_storeu_si256(reinterpret_cast<__m256i*>(p), a.m); +} + +/** + * @brief Store lowest N (vector width) bytes into an unaligned address. + */ +ASTCENC_SIMD_INLINE void store_nbytes(vint8 a, uint8_t* p) +{ + // This is the most logical implementation, but the convenience intrinsic + // is missing on older compilers (supported in g++ 9 and clang++ 9). + // _mm_storeu_si64(ptr, _mm256_extracti128_si256(v.m, 0)) + _mm_storel_epi64(reinterpret_cast<__m128i*>(p), _mm256_extracti128_si256(a.m, 0)); +} + +/** + * @brief Gather N (vector width) indices from the array. + */ +ASTCENC_SIMD_INLINE vint8 gatheri(const int* base, vint8 indices) +{ + return vint8(_mm256_i32gather_epi32(base, indices.m, 4)); +} + +/** + * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector. + */ +ASTCENC_SIMD_INLINE vint8 pack_low_bytes(vint8 v) +{ + __m256i shuf = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 28, 24, 20, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 8, 4, 0); + __m256i a = _mm256_shuffle_epi8(v.m, shuf); + __m128i a0 = _mm256_extracti128_si256(a, 0); + __m128i a1 = _mm256_extracti128_si256(a, 1); + __m128i b = _mm_unpacklo_epi32(a0, a1); + + __m256i r = astcenc_mm256_set_m128i(b, b); + return vint8(r); +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vint8 select(vint8 a, vint8 b, vmask8 cond) +{ + __m256i condi = _mm256_castps_si256(cond.m); + return vint8(_mm256_blendv_epi8(a.m, b.m, condi)); +} + +// ============================================================================ +// vfloat4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vfloat8 operator+(vfloat8 a, vfloat8 b) +{ + return vfloat8(_mm256_add_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector incremental addition. + */ +ASTCENC_SIMD_INLINE vfloat8& operator+=(vfloat8& a, const vfloat8& b) +{ + a = a + b; + return a; +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vfloat8 operator-(vfloat8 a, vfloat8 b) +{ + return vfloat8(_mm256_sub_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vfloat8 operator*(vfloat8 a, vfloat8 b) +{ + return vfloat8(_mm256_mul_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by scalar multiplication. + */ +ASTCENC_SIMD_INLINE vfloat8 operator*(vfloat8 a, float b) +{ + return vfloat8(_mm256_mul_ps(a.m, _mm256_set1_ps(b))); +} + +/** + * @brief Overload: scalar by vector multiplication. + */ +ASTCENC_SIMD_INLINE vfloat8 operator*(float a, vfloat8 b) +{ + return vfloat8(_mm256_mul_ps(_mm256_set1_ps(a), b.m)); +} + +/** + * @brief Overload: vector by vector division. + */ +ASTCENC_SIMD_INLINE vfloat8 operator/(vfloat8 a, vfloat8 b) +{ + return vfloat8(_mm256_div_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by scalar division. + */ +ASTCENC_SIMD_INLINE vfloat8 operator/(vfloat8 a, float b) +{ + return vfloat8(_mm256_div_ps(a.m, _mm256_set1_ps(b))); +} + + +/** + * @brief Overload: scalar by vector division. + */ +ASTCENC_SIMD_INLINE vfloat8 operator/(float a, vfloat8 b) +{ + return vfloat8(_mm256_div_ps(_mm256_set1_ps(a), b.m)); +} + + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask8 operator==(vfloat8 a, vfloat8 b) +{ + return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_EQ_OQ)); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask8 operator!=(vfloat8 a, vfloat8 b) +{ + return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_NEQ_OQ)); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask8 operator<(vfloat8 a, vfloat8 b) +{ + return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_LT_OQ)); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask8 operator>(vfloat8 a, vfloat8 b) +{ + return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_GT_OQ)); +} + +/** + * @brief Overload: vector by vector less than or equal. + */ +ASTCENC_SIMD_INLINE vmask8 operator<=(vfloat8 a, vfloat8 b) +{ + return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_LE_OQ)); +} + +/** + * @brief Overload: vector by vector greater than or equal. + */ +ASTCENC_SIMD_INLINE vmask8 operator>=(vfloat8 a, vfloat8 b) +{ + return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_GE_OQ)); +} + +/** + * @brief Return the min vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 min(vfloat8 a, vfloat8 b) +{ + return vfloat8(_mm256_min_ps(a.m, b.m)); +} + +/** + * @brief Return the min vector of a vector and a scalar. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 min(vfloat8 a, float b) +{ + return min(a, vfloat8(b)); +} + +/** + * @brief Return the max vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 max(vfloat8 a, vfloat8 b) +{ + return vfloat8(_mm256_max_ps(a.m, b.m)); +} + +/** + * @brief Return the max vector of a vector and a scalar. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 max(vfloat8 a, float b) +{ + return max(a, vfloat8(b)); +} + +/** + * @brief Return the clamped value between min and max. + * + * It is assumed that neither @c min nor @c max are NaN values. If @c a is NaN + * then @c min will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 clamp(float min, float max, vfloat8 a) +{ + // Do not reorder - second operand will return if either is NaN + a.m = _mm256_max_ps(a.m, _mm256_set1_ps(min)); + a.m = _mm256_min_ps(a.m, _mm256_set1_ps(max)); + return a; +} + +/** + * @brief Return a clamped value between 0.0f and max. + * + * It is assumed that @c max is not a NaN value. If @c a is NaN then zero will + * be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 clampz(float max, vfloat8 a) +{ + a.m = _mm256_max_ps(a.m, _mm256_setzero_ps()); + a.m = _mm256_min_ps(a.m, _mm256_set1_ps(max)); + return a; +} + +/** + * @brief Return a clamped value between 0.0f and 1.0f. + * + * If @c a is NaN then zero will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat8 clampzo(vfloat8 a) +{ + a.m = _mm256_max_ps(a.m, _mm256_setzero_ps()); + a.m = _mm256_min_ps(a.m, _mm256_set1_ps(1.0f)); + return a; +} + +/** + * @brief Return the absolute value of the float vector. + */ +ASTCENC_SIMD_INLINE vfloat8 abs(vfloat8 a) +{ + __m256 msk = _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff)); + return vfloat8(_mm256_and_ps(a.m, msk)); +} + +/** + * @brief Return a float rounded to the nearest integer value. + */ +ASTCENC_SIMD_INLINE vfloat8 round(vfloat8 a) +{ + constexpr int flags = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC; + return vfloat8(_mm256_round_ps(a.m, flags)); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat8 hmin(vfloat8 a) +{ + __m128 vlow = _mm256_castps256_ps128(a.m); + __m128 vhigh = _mm256_extractf128_ps(a.m, 1); + vlow = _mm_min_ps(vlow, vhigh); + + // First do an horizontal reduction. + __m128 shuf = _mm_shuffle_ps(vlow, vlow, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 mins = _mm_min_ps(vlow, shuf); + shuf = _mm_movehl_ps(shuf, mins); + mins = _mm_min_ss(mins, shuf); + + // This is the most logical implementation, but the convenience intrinsic + // is missing on older compilers (supported in g++ 9 and clang++ 9). + //__m256i r = _mm256_set_m128(m, m) + __m256 r = _mm256_insertf128_ps(_mm256_castps128_ps256(mins), mins, 1); + + return vfloat8(_mm256_permute_ps(r, 0)); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE float hmin_s(vfloat8 a) +{ + return hmin(a).lane<0>(); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat8 hmax(vfloat8 a) +{ + __m128 vlow = _mm256_castps256_ps128(a.m); + __m128 vhigh = _mm256_extractf128_ps(a.m, 1); + vhigh = _mm_max_ps(vlow, vhigh); + + // First do an horizontal reduction. + __m128 shuf = _mm_shuffle_ps(vhigh, vhigh, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 maxs = _mm_max_ps(vhigh, shuf); + shuf = _mm_movehl_ps(shuf,maxs); + maxs = _mm_max_ss(maxs, shuf); + + // This is the most logical implementation, but the convenience intrinsic + // is missing on older compilers (supported in g++ 9 and clang++ 9). + //__m256i r = _mm256_set_m128(m, m) + __m256 r = _mm256_insertf128_ps(_mm256_castps128_ps256(maxs), maxs, 1); + return vfloat8(_mm256_permute_ps(r, 0)); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE float hmax_s(vfloat8 a) +{ + return hmax(a).lane<0>(); +} + +/** + * @brief Return the horizontal sum of a vector. + */ +ASTCENC_SIMD_INLINE float hadd_s(vfloat8 a) +{ + // Two sequential 4-wide adds gives invariance with 4-wide code + vfloat4 lo(_mm256_extractf128_ps(a.m, 0)); + vfloat4 hi(_mm256_extractf128_ps(a.m, 1)); + return hadd_s(lo) + hadd_s(hi); +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat8 select(vfloat8 a, vfloat8 b, vmask8 cond) +{ + return vfloat8(_mm256_blendv_ps(a.m, b.m, cond.m)); +} + +/** + * @brief Return lanes from @c b if MSB of @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat8 select_msb(vfloat8 a, vfloat8 b, vmask8 cond) +{ + return vfloat8(_mm256_blendv_ps(a.m, b.m, cond.m)); +} + +/** + * @brief Accumulate lane-wise sums for a vector, folded 4-wide. + * + * This is invariant with 4-wide implementations. + */ +ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat8 a) +{ + vfloat4 lo(_mm256_extractf128_ps(a.m, 0)); + haccumulate(accum, lo); + + vfloat4 hi(_mm256_extractf128_ps(a.m, 1)); + haccumulate(accum, hi); +} + +/** + * @brief Accumulate lane-wise sums for a vector. + * + * This is NOT invariant with 4-wide implementations. + */ +ASTCENC_SIMD_INLINE void haccumulate(vfloat8& accum, vfloat8 a) +{ + accum += a; +} + +/** + * @brief Accumulate masked lane-wise sums for a vector, folded 4-wide. + * + * This is invariant with 4-wide implementations. + */ +ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat8 a, vmask8 m) +{ + a = select(vfloat8::zero(), a, m); + haccumulate(accum, a); +} + +/** + * @brief Accumulate masked lane-wise sums for a vector. + * + * This is NOT invariant with 4-wide implementations. + */ +ASTCENC_SIMD_INLINE void haccumulate(vfloat8& accum, vfloat8 a, vmask8 m) +{ + a = select(vfloat8::zero(), a, m); + haccumulate(accum, a); +} + +/** + * @brief Return the sqrt of the lanes in the vector. + */ +ASTCENC_SIMD_INLINE vfloat8 sqrt(vfloat8 a) +{ + return vfloat8(_mm256_sqrt_ps(a.m)); +} + +/** + * @brief Load a vector of gathered results from an array; + */ +ASTCENC_SIMD_INLINE vfloat8 gatherf(const float* base, vint8 indices) +{ + return vfloat8(_mm256_i32gather_ps(base, indices.m, 4)); +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vfloat8 a, float* p) +{ + _mm256_storeu_ps(p, a.m); +} + +/** + * @brief Store a vector to a 32B aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vfloat8 a, float* p) +{ + _mm256_store_ps(p, a.m); +} + +/** + * @brief Return a integer value for a float vector, using truncation. + */ +ASTCENC_SIMD_INLINE vint8 float_to_int(vfloat8 a) +{ + return vint8(_mm256_cvttps_epi32(a.m)); +} + +/** + * @brief Return a integer value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint8 float_to_int_rtn(vfloat8 a) +{ + a = round(a); + return vint8(_mm256_cvttps_epi32(a.m)); +} + + +/** + * @brief Return a float value for an integer vector. + */ +ASTCENC_SIMD_INLINE vfloat8 int_to_float(vint8 a) +{ + return vfloat8(_mm256_cvtepi32_ps(a.m)); +} + +/** + * @brief Return a float value as an integer bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the first half of that flip. + */ +ASTCENC_SIMD_INLINE vint8 float_as_int(vfloat8 a) +{ + return vint8(_mm256_castps_si256(a.m)); +} + +/** + * @brief Return a integer value as a float bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the second half of that flip. + */ +ASTCENC_SIMD_INLINE vfloat8 int_as_float(vint8 a) +{ + return vfloat8(_mm256_castsi256_ps(a.m)); +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint8& t0p) +{ + // AVX2 duplicates the table within each 128-bit lane + __m128i t0n = t0.m; + t0p = vint8(astcenc_mm256_set_m128i(t0n, t0n)); +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint8& t0p, vint8& t1p) +{ + // AVX2 duplicates the table within each 128-bit lane + __m128i t0n = t0.m; + t0p = vint8(astcenc_mm256_set_m128i(t0n, t0n)); + + __m128i t1n = _mm_xor_si128(t0.m, t1.m); + t1p = vint8(astcenc_mm256_set_m128i(t1n, t1n)); +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare( + vint4 t0, vint4 t1, vint4 t2, vint4 t3, + vint8& t0p, vint8& t1p, vint8& t2p, vint8& t3p) +{ + // AVX2 duplicates the table within each 128-bit lane + __m128i t0n = t0.m; + t0p = vint8(astcenc_mm256_set_m128i(t0n, t0n)); + + __m128i t1n = _mm_xor_si128(t0.m, t1.m); + t1p = vint8(astcenc_mm256_set_m128i(t1n, t1n)); + + __m128i t2n = _mm_xor_si128(t1.m, t2.m); + t2p = vint8(astcenc_mm256_set_m128i(t2n, t2n)); + + __m128i t3n = _mm_xor_si128(t2.m, t3.m); + t3p = vint8(astcenc_mm256_set_m128i(t3n, t3n)); +} + +/** + * @brief Perform an 8-bit 16-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint8 vtable_8bt_32bi(vint8 t0, vint8 idx) +{ + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m256i idxx = _mm256_or_si256(idx.m, _mm256_set1_epi32(static_cast<int>(0xFFFFFF00))); + + __m256i result = _mm256_shuffle_epi8(t0.m, idxx); + return vint8(result); +} + +/** + * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint8 vtable_8bt_32bi(vint8 t0, vint8 t1, vint8 idx) +{ + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m256i idxx = _mm256_or_si256(idx.m, _mm256_set1_epi32(static_cast<int>(0xFFFFFF00))); + + __m256i result = _mm256_shuffle_epi8(t0.m, idxx); + idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16)); + + __m256i result2 = _mm256_shuffle_epi8(t1.m, idxx); + result = _mm256_xor_si256(result, result2); + return vint8(result); +} + +/** + * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint8 vtable_8bt_32bi(vint8 t0, vint8 t1, vint8 t2, vint8 t3, vint8 idx) +{ + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m256i idxx = _mm256_or_si256(idx.m, _mm256_set1_epi32(static_cast<int>(0xFFFFFF00))); + + __m256i result = _mm256_shuffle_epi8(t0.m, idxx); + idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16)); + + __m256i result2 = _mm256_shuffle_epi8(t1.m, idxx); + result = _mm256_xor_si256(result, result2); + idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16)); + + result2 = _mm256_shuffle_epi8(t2.m, idxx); + result = _mm256_xor_si256(result, result2); + idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16)); + + result2 = _mm256_shuffle_epi8(t3.m, idxx); + result = _mm256_xor_si256(result, result2); + + return vint8(result); +} + +/** + * @brief Return a vector of interleaved RGBA data. + * + * Input vectors have the value stored in the bottom 8 bits of each lane, + * with high bits set to zero. + * + * Output vector stores a single RGBA texel packed in each lane. + */ +ASTCENC_SIMD_INLINE vint8 interleave_rgba8(vint8 r, vint8 g, vint8 b, vint8 a) +{ + return r + lsl<8>(g) + lsl<16>(b) + lsl<24>(a); +} + +/** + * @brief Store a vector, skipping masked lanes. + * + * All masked lanes must be at the end of vector, after all non-masked lanes. + */ +ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint8 data, vmask8 mask) +{ + _mm256_maskstore_epi32(base, _mm256_castps_si256(mask.m), data.m); +} + +/** + * @brief Debug function to print a vector of ints. + */ +ASTCENC_SIMD_INLINE void print(vint8 a) +{ + alignas(ASTCENC_VECALIGN) int v[8]; + storea(a, v); + printf("v8_i32:\n %8d %8d %8d %8d %8d %8d %8d %8d\n", + v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); +} + +/** + * @brief Debug function to print a vector of ints. + */ +ASTCENC_SIMD_INLINE void printx(vint8 a) +{ + alignas(ASTCENC_VECALIGN) int v[8]; + storea(a, v); + printf("v8_i32:\n %08x %08x %08x %08x %08x %08x %08x %08x\n", + v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); +} + +/** + * @brief Debug function to print a vector of floats. + */ +ASTCENC_SIMD_INLINE void print(vfloat8 a) +{ + alignas(ASTCENC_VECALIGN) float v[8]; + storea(a, v); + printf("v8_f32:\n %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f\n", + static_cast<double>(v[0]), static_cast<double>(v[1]), + static_cast<double>(v[2]), static_cast<double>(v[3]), + static_cast<double>(v[4]), static_cast<double>(v[5]), + static_cast<double>(v[6]), static_cast<double>(v[7])); +} + +/** + * @brief Debug function to print a vector of masks. + */ +ASTCENC_SIMD_INLINE void print(vmask8 a) +{ + print(select(vint8(0), vint8(1), a)); +} + +#endif // #ifndef ASTC_VECMATHLIB_AVX2_8_H_INCLUDED diff --git a/thirdparty/astcenc/astcenc_vecmathlib_common_4.h b/thirdparty/astcenc/astcenc_vecmathlib_common_4.h new file mode 100644 index 0000000000..86ee4fd3e1 --- /dev/null +++ b/thirdparty/astcenc/astcenc_vecmathlib_common_4.h @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2020-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Generic 4x32-bit vector functions. + * + * This module implements generic 4-wide vector functions that are valid for + * all instruction sets, typically implemented using lower level 4-wide + * operations that are ISA-specific. + */ + +#ifndef ASTC_VECMATHLIB_COMMON_4_H_INCLUDED +#define ASTC_VECMATHLIB_COMMON_4_H_INCLUDED + +#ifndef ASTCENC_SIMD_INLINE + #error "Include astcenc_vecmathlib.h, do not include directly" +#endif + +#include <cstdio> + +// ============================================================================ +// vmask4 operators and functions +// ============================================================================ + +/** + * @brief True if any lanes are enabled, false otherwise. + */ +ASTCENC_SIMD_INLINE bool any(vmask4 a) +{ + return mask(a) != 0; +} + +/** + * @brief True if all lanes are enabled, false otherwise. + */ +ASTCENC_SIMD_INLINE bool all(vmask4 a) +{ + return mask(a) == 0xF; +} + +// ============================================================================ +// vint4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by scalar addition. + */ +ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, int b) +{ + return a + vint4(b); +} + +/** + * @brief Overload: vector by vector incremental addition. + */ +ASTCENC_SIMD_INLINE vint4& operator+=(vint4& a, const vint4& b) +{ + a = a + b; + return a; +} + +/** + * @brief Overload: vector by scalar subtraction. + */ +ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, int b) +{ + return a - vint4(b); +} + +/** + * @brief Overload: vector by scalar multiplication. + */ +ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, int b) +{ + return a * vint4(b); +} + +/** + * @brief Overload: vector by scalar bitwise or. + */ +ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, int b) +{ + return a | vint4(b); +} + +/** + * @brief Overload: vector by scalar bitwise and. + */ +ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, int b) +{ + return a & vint4(b); +} + +/** + * @brief Overload: vector by scalar bitwise xor. + */ +ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, int b) +{ + return a ^ vint4(b); +} + +/** + * @brief Return the clamped value between min and max. + */ +ASTCENC_SIMD_INLINE vint4 clamp(int minv, int maxv, vint4 a) +{ + return min(max(a, vint4(minv)), vint4(maxv)); +} + +/** + * @brief Return the horizontal sum of RGB vector lanes as a scalar. + */ +ASTCENC_SIMD_INLINE int hadd_rgb_s(vint4 a) +{ + return a.lane<0>() + a.lane<1>() + a.lane<2>(); +} + +// ============================================================================ +// vfloat4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector incremental addition. + */ +ASTCENC_SIMD_INLINE vfloat4& operator+=(vfloat4& a, const vfloat4& b) +{ + a = a + b; + return a; +} + +/** + * @brief Overload: vector by scalar addition. + */ +ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, float b) +{ + return a + vfloat4(b); +} + +/** + * @brief Overload: vector by scalar subtraction. + */ +ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, float b) +{ + return a - vfloat4(b); +} + +/** + * @brief Overload: vector by scalar multiplication. + */ +ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, float b) +{ + return a * vfloat4(b); +} + +/** + * @brief Overload: scalar by vector multiplication. + */ +ASTCENC_SIMD_INLINE vfloat4 operator*(float a, vfloat4 b) +{ + return vfloat4(a) * b; +} + +/** + * @brief Overload: vector by scalar division. + */ +ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, float b) +{ + return a / vfloat4(b); +} + +/** + * @brief Overload: scalar by vector division. + */ +ASTCENC_SIMD_INLINE vfloat4 operator/(float a, vfloat4 b) +{ + return vfloat4(a) / b; +} + +/** + * @brief Return the min vector of a vector and a scalar. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, float b) +{ + return min(a, vfloat4(b)); +} + +/** + * @brief Return the max vector of a vector and a scalar. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, float b) +{ + return max(a, vfloat4(b)); +} + +/** + * @brief Return the clamped value between min and max. + * + * It is assumed that neither @c min nor @c max are NaN values. If @c a is NaN + * then @c min will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 clamp(float minv, float maxv, vfloat4 a) +{ + // Do not reorder - second operand will return if either is NaN + return min(max(a, minv), maxv); +} + +/** + * @brief Return the clamped value between 0.0f and max. + * + * It is assumed that @c max is not a NaN value. If @c a is NaN then zero will + * be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 clampz(float maxv, vfloat4 a) +{ + // Do not reorder - second operand will return if either is NaN + return min(max(a, vfloat4::zero()), maxv); +} + +/** + * @brief Return the clamped value between 0.0f and 1.0f. + * + * If @c a is NaN then zero will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 clampzo(vfloat4 a) +{ + // Do not reorder - second operand will return if either is NaN + return min(max(a, vfloat4::zero()), 1.0f); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE float hmin_s(vfloat4 a) +{ + return hmin(a).lane<0>(); +} + +/** + * @brief Return the horizontal min of RGB vector lanes as a scalar. + */ +ASTCENC_SIMD_INLINE float hmin_rgb_s(vfloat4 a) +{ + a.set_lane<3>(a.lane<0>()); + return hmin_s(a); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE float hmax_s(vfloat4 a) +{ + return hmax(a).lane<0>(); +} + +/** + * @brief Accumulate lane-wise sums for a vector. + */ +ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat4 a) +{ + accum = accum + a; +} + +/** + * @brief Accumulate lane-wise sums for a masked vector. + */ +ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat4 a, vmask4 m) +{ + a = select(vfloat4::zero(), a, m); + haccumulate(accum, a); +} + +/** + * @brief Return the horizontal sum of RGB vector lanes as a scalar. + */ +ASTCENC_SIMD_INLINE float hadd_rgb_s(vfloat4 a) +{ + return a.lane<0>() + a.lane<1>() + a.lane<2>(); +} + +#if !defined(ASTCENC_USE_NATIVE_DOT_PRODUCT) + +/** + * @brief Return the dot product for the full 4 lanes, returning scalar. + */ +ASTCENC_SIMD_INLINE float dot_s(vfloat4 a, vfloat4 b) +{ + vfloat4 m = a * b; + return hadd_s(m); +} + +/** + * @brief Return the dot product for the full 4 lanes, returning vector. + */ +ASTCENC_SIMD_INLINE vfloat4 dot(vfloat4 a, vfloat4 b) +{ + vfloat4 m = a * b; + return vfloat4(hadd_s(m)); +} + +/** + * @brief Return the dot product for the bottom 3 lanes, returning scalar. + */ +ASTCENC_SIMD_INLINE float dot3_s(vfloat4 a, vfloat4 b) +{ + vfloat4 m = a * b; + return hadd_rgb_s(m); +} + +/** + * @brief Return the dot product for the bottom 3 lanes, returning vector. + */ +ASTCENC_SIMD_INLINE vfloat4 dot3(vfloat4 a, vfloat4 b) +{ + vfloat4 m = a * b; + float d3 = hadd_rgb_s(m); + return vfloat4(d3, d3, d3, 0.0f); +} + +#endif + +#if !defined(ASTCENC_USE_NATIVE_POPCOUNT) + +/** + * @brief Population bit count. + * + * @param v The value to population count. + * + * @return The number of 1 bits. + */ +static inline int popcount(uint64_t v) +{ + uint64_t mask1 = 0x5555555555555555ULL; + uint64_t mask2 = 0x3333333333333333ULL; + uint64_t mask3 = 0x0F0F0F0F0F0F0F0FULL; + v -= (v >> 1) & mask1; + v = (v & mask2) + ((v >> 2) & mask2); + v += v >> 4; + v &= mask3; + v *= 0x0101010101010101ULL; + v >>= 56; + return static_cast<int>(v); +} + +#endif + +/** + * @brief Apply signed bit transfer. + * + * @param input0 The first encoded endpoint. + * @param input1 The second encoded endpoint. + */ +static ASTCENC_SIMD_INLINE void bit_transfer_signed( + vint4& input0, + vint4& input1 +) { + input1 = lsr<1>(input1) | (input0 & 0x80); + input0 = lsr<1>(input0) & 0x3F; + + vmask4 mask = (input0 & 0x20) != vint4::zero(); + input0 = select(input0, input0 - 0x40, mask); +} + +/** + * @brief Debug function to print a vector of ints. + */ +ASTCENC_SIMD_INLINE void print(vint4 a) +{ + alignas(16) int v[4]; + storea(a, v); + printf("v4_i32:\n %8d %8d %8d %8d\n", + v[0], v[1], v[2], v[3]); +} + +/** + * @brief Debug function to print a vector of ints. + */ +ASTCENC_SIMD_INLINE void printx(vint4 a) +{ + alignas(16) int v[4]; + storea(a, v); + printf("v4_i32:\n %08x %08x %08x %08x\n", + v[0], v[1], v[2], v[3]); +} + +/** + * @brief Debug function to print a vector of floats. + */ +ASTCENC_SIMD_INLINE void print(vfloat4 a) +{ + alignas(16) float v[4]; + storea(a, v); + printf("v4_f32:\n %0.4f %0.4f %0.4f %0.4f\n", + static_cast<double>(v[0]), static_cast<double>(v[1]), + static_cast<double>(v[2]), static_cast<double>(v[3])); +} + +/** + * @brief Debug function to print a vector of masks. + */ +ASTCENC_SIMD_INLINE void print(vmask4 a) +{ + print(select(vint4(0), vint4(1), a)); +} + +#endif // #ifndef ASTC_VECMATHLIB_COMMON_4_H_INCLUDED diff --git a/thirdparty/astcenc/astcenc_vecmathlib_neon_4.h b/thirdparty/astcenc/astcenc_vecmathlib_neon_4.h new file mode 100644 index 0000000000..e742eae6cb --- /dev/null +++ b/thirdparty/astcenc/astcenc_vecmathlib_neon_4.h @@ -0,0 +1,1072 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2019-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief 4x32-bit vectors, implemented using Armv8-A NEON. + * + * This module implements 4-wide 32-bit float, int, and mask vectors for + * Armv8-A NEON. + * + * There is a baseline level of functionality provided by all vector widths and + * implementations. This is implemented using identical function signatures, + * modulo data type, so we can use them as substitutable implementations in VLA + * code. + * + * The 4-wide vectors are also used as a fixed-width type, and significantly + * extend the functionality above that available to VLA code. + */ + +#ifndef ASTC_VECMATHLIB_NEON_4_H_INCLUDED +#define ASTC_VECMATHLIB_NEON_4_H_INCLUDED + +#ifndef ASTCENC_SIMD_INLINE + #error "Include astcenc_vecmathlib.h, do not include directly" +#endif + +#include <cstdio> + +// ============================================================================ +// vfloat4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide floats. + */ +struct vfloat4 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vfloat4() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using loada() which is better with vectors if data is aligned + * to vector length. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(const float *p) + { + m = vld1q_f32(p); + } + + /** + * @brief Construct from 1 scalar value replicated across all lanes. + * + * Consider using zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float a) + { + m = vdupq_n_f32(a); + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float a, float b, float c, float d) + { + float v[4] { a, b, c, d }; + m = vld1q_f32(v); + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float32x4_t a) + { + m = a; + } + + /** + * @brief Get the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE float lane() const + { + return vgetq_lane_f32(m, l); + } + + /** + * @brief Set the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE void set_lane(float a) + { + m = vsetq_lane_f32(a, m, l); + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vfloat4 zero() + { + return vfloat4(vdupq_n_f32(0.0f)); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p) + { + return vfloat4(vld1q_dup_f32(p)); + } + + /** + * @brief Factory that returns a vector loaded from 16B aligned memory. + */ + static ASTCENC_SIMD_INLINE vfloat4 loada(const float* p) + { + return vfloat4(vld1q_f32(p)); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vfloat4 lane_id() + { + alignas(16) float data[4] { 0.0f, 1.0f, 2.0f, 3.0f }; + return vfloat4(vld1q_f32(data)); + } + + /** + * @brief Return a swizzled float 2. + */ + template <int l0, int l1> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(lane<l0>(), lane<l1>(), 0.0f, 0.0f); + } + + /** + * @brief Return a swizzled float 3. + */ + template <int l0, int l1, int l2> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), 0.0f); + } + + /** + * @brief Return a swizzled float 4. + */ + template <int l0, int l1, int l2, int l3> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), lane<l3>()); + } + + /** + * @brief The vector ... + */ + float32x4_t m; +}; + +// ============================================================================ +// vint4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide ints. + */ +struct vint4 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vint4() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using loada() which is better with vectors if data is aligned + * to vector length. + */ + ASTCENC_SIMD_INLINE explicit vint4(const int *p) + { + m = vld1q_s32(p); + } + + /** + * @brief Construct from 4 uint8_t loaded from an unaligned address. + */ + ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p) + { + // Cast is safe - NEON loads are allowed to be unaligned + uint32x2_t t8 = vld1_dup_u32(reinterpret_cast<const uint32_t*>(p)); + uint16x4_t t16 = vget_low_u16(vmovl_u8(vreinterpret_u8_u32(t8))); + m = vreinterpretq_s32_u32(vmovl_u16(t16)); + } + + /** + * @brief Construct from 1 scalar value replicated across all lanes. + * + * Consider using vfloat4::zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vint4(int a) + { + m = vdupq_n_s32(a); + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint4(int a, int b, int c, int d) + { + int v[4] { a, b, c, d }; + m = vld1q_s32(v); + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint4(int32x4_t a) + { + m = a; + } + + /** + * @brief Get the scalar from a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE int lane() const + { + return vgetq_lane_s32(m, l); + } + + /** + * @brief Set the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE void set_lane(int a) + { + m = vsetq_lane_s32(a, m, l); + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vint4 zero() + { + return vint4(0); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vint4 load1(const int* p) + { + return vint4(*p); + } + + /** + * @brief Factory that returns a vector loaded from 16B aligned memory. + */ + static ASTCENC_SIMD_INLINE vint4 loada(const int* p) + { + return vint4(p); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vint4 lane_id() + { + alignas(16) static const int data[4] { 0, 1, 2, 3 }; + return vint4(vld1q_s32(data)); + } + + /** + * @brief The vector ... + */ + int32x4_t m; +}; + +// ============================================================================ +// vmask4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide control plane masks. + */ +struct vmask4 +{ + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(uint32x4_t a) + { + m = a; + } + +#if !defined(_MSC_VER) + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(int32x4_t a) + { + m = vreinterpretq_u32_s32(a); + } +#endif + + /** + * @brief Construct from 1 scalar value. + */ + ASTCENC_SIMD_INLINE explicit vmask4(bool a) + { + m = vreinterpretq_u32_s32(vdupq_n_s32(a == true ? -1 : 0)); + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(bool a, bool b, bool c, bool d) + { + int v[4] { + a == true ? -1 : 0, + b == true ? -1 : 0, + c == true ? -1 : 0, + d == true ? -1 : 0 + }; + + int32x4_t ms = vld1q_s32(v); + m = vreinterpretq_u32_s32(ms); + } + + /** + * @brief Get the scalar from a single lane. + */ + template <int32_t l> ASTCENC_SIMD_INLINE uint32_t lane() const + { + return vgetq_lane_u32(m, l); + } + + /** + * @brief The vector ... + */ + uint32x4_t m; +}; + +// ============================================================================ +// vmask4 operators and functions +// ============================================================================ + +/** + * @brief Overload: mask union (or). + */ +ASTCENC_SIMD_INLINE vmask4 operator|(vmask4 a, vmask4 b) +{ + return vmask4(vorrq_u32(a.m, b.m)); +} + +/** + * @brief Overload: mask intersect (and). + */ +ASTCENC_SIMD_INLINE vmask4 operator&(vmask4 a, vmask4 b) +{ + return vmask4(vandq_u32(a.m, b.m)); +} + +/** + * @brief Overload: mask difference (xor). + */ +ASTCENC_SIMD_INLINE vmask4 operator^(vmask4 a, vmask4 b) +{ + return vmask4(veorq_u32(a.m, b.m)); +} + +/** + * @brief Overload: mask invert (not). + */ +ASTCENC_SIMD_INLINE vmask4 operator~(vmask4 a) +{ + return vmask4(vmvnq_u32(a.m)); +} + +/** + * @brief Return a 4-bit mask code indicating mask status. + * + * bit0 = lane 0 + */ +ASTCENC_SIMD_INLINE unsigned int mask(vmask4 a) +{ + static const int shifta[4] { 0, 1, 2, 3 }; + static const int32x4_t shift = vld1q_s32(shifta); + + uint32x4_t tmp = vshrq_n_u32(a.m, 31); + return vaddvq_u32(vshlq_u32(tmp, shift)); +} + +// ============================================================================ +// vint4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, vint4 b) +{ + return vint4(vaddq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, vint4 b) +{ + return vint4(vsubq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, vint4 b) +{ + return vint4(vmulq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector bit invert. + */ +ASTCENC_SIMD_INLINE vint4 operator~(vint4 a) +{ + return vint4(vmvnq_s32(a.m)); +} + +/** + * @brief Overload: vector by vector bitwise or. + */ +ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, vint4 b) +{ + return vint4(vorrq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector bitwise and. + */ +ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, vint4 b) +{ + return vint4(vandq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector bitwise xor. + */ +ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, vint4 b) +{ + return vint4(veorq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask4 operator==(vint4 a, vint4 b) +{ + return vmask4(vceqq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask4 operator!=(vint4 a, vint4 b) +{ + return ~vmask4(vceqq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask4 operator<(vint4 a, vint4 b) +{ + return vmask4(vcltq_s32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask4 operator>(vint4 a, vint4 b) +{ + return vmask4(vcgtq_s32(a.m, b.m)); +} + +/** + * @brief Logical shift left. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 lsl(vint4 a) +{ + return vint4(vshlq_s32(a.m, vdupq_n_s32(s))); +} + +/** + * @brief Logical shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 lsr(vint4 a) +{ + uint32x4_t ua = vreinterpretq_u32_s32(a.m); + ua = vshlq_u32(ua, vdupq_n_s32(-s)); + return vint4(vreinterpretq_s32_u32(ua)); +} + +/** + * @brief Arithmetic shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 asr(vint4 a) +{ + return vint4(vshlq_s32(a.m, vdupq_n_s32(-s))); +} + +/** + * @brief Return the min vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint4 min(vint4 a, vint4 b) +{ + return vint4(vminq_s32(a.m, b.m)); +} + +/** + * @brief Return the max vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint4 max(vint4 a, vint4 b) +{ + return vint4(vmaxq_s32(a.m, b.m)); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vint4 hmin(vint4 a) +{ + return vint4(vminvq_s32(a.m)); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vint4 hmax(vint4 a) +{ + return vint4(vmaxvq_s32(a.m)); +} + +/** + * @brief Return the horizontal sum of a vector. + */ +ASTCENC_SIMD_INLINE int hadd_s(vint4 a) +{ + int32x2_t t = vadd_s32(vget_high_s32(a.m), vget_low_s32(a.m)); + return vget_lane_s32(vpadd_s32(t, t), 0); +} + +/** + * @brief Store a vector to a 16B aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vint4 a, int* p) +{ + vst1q_s32(p, a.m); +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vint4 a, int* p) +{ + vst1q_s32(p, a.m); +} + +/** + * @brief Store lowest N (vector width) bytes into an unaligned address. + */ +ASTCENC_SIMD_INLINE void store_nbytes(vint4 a, uint8_t* p) +{ + vst1q_lane_s32(reinterpret_cast<int32_t*>(p), a.m, 0); +} + +/** + * @brief Gather N (vector width) indices from the array. + */ +ASTCENC_SIMD_INLINE vint4 gatheri(const int* base, vint4 indices) +{ + alignas(16) int idx[4]; + storea(indices, idx); + alignas(16) int vals[4]; + vals[0] = base[idx[0]]; + vals[1] = base[idx[1]]; + vals[2] = base[idx[2]]; + vals[3] = base[idx[3]]; + return vint4(vals); +} + +/** + * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector. + */ +ASTCENC_SIMD_INLINE vint4 pack_low_bytes(vint4 a) +{ + alignas(16) uint8_t shuf[16] { + 0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + uint8x16_t idx = vld1q_u8(shuf); + int8x16_t av = vreinterpretq_s8_s32(a.m); + return vint4(vreinterpretq_s32_s8(vqtbl1q_s8(av, idx))); +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vint4 select(vint4 a, vint4 b, vmask4 cond) +{ + return vint4(vbslq_s32(cond.m, b.m, a.m)); +} + +// ============================================================================ +// vfloat4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, vfloat4 b) +{ + return vfloat4(vaddq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, vfloat4 b) +{ + return vfloat4(vsubq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, vfloat4 b) +{ + return vfloat4(vmulq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector division. + */ +ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, vfloat4 b) +{ + return vfloat4(vdivq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask4 operator==(vfloat4 a, vfloat4 b) +{ + return vmask4(vceqq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask4 operator!=(vfloat4 a, vfloat4 b) +{ + return vmask4(vmvnq_u32(vceqq_f32(a.m, b.m))); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask4 operator<(vfloat4 a, vfloat4 b) +{ + return vmask4(vcltq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask4 operator>(vfloat4 a, vfloat4 b) +{ + return vmask4(vcgtq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector less than or equal. + */ +ASTCENC_SIMD_INLINE vmask4 operator<=(vfloat4 a, vfloat4 b) +{ + return vmask4(vcleq_f32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector greater than or equal. + */ +ASTCENC_SIMD_INLINE vmask4 operator>=(vfloat4 a, vfloat4 b) +{ + return vmask4(vcgeq_f32(a.m, b.m)); +} + +/** + * @brief Return the min vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, vfloat4 b) +{ + // Do not reorder - second operand will return if either is NaN + return vfloat4(vminnmq_f32(a.m, b.m)); +} + +/** + * @brief Return the max vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, vfloat4 b) +{ + // Do not reorder - second operand will return if either is NaN + return vfloat4(vmaxnmq_f32(a.m, b.m)); +} + +/** + * @brief Return the absolute value of the float vector. + */ +ASTCENC_SIMD_INLINE vfloat4 abs(vfloat4 a) +{ + float32x4_t zero = vdupq_n_f32(0.0f); + float32x4_t inv = vsubq_f32(zero, a.m); + return vfloat4(vmaxq_f32(a.m, inv)); +} + +/** + * @brief Return a float rounded to the nearest integer value. + */ +ASTCENC_SIMD_INLINE vfloat4 round(vfloat4 a) +{ + return vfloat4(vrndnq_f32(a.m)); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat4 hmin(vfloat4 a) +{ + return vfloat4(vminvq_f32(a.m)); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat4 hmax(vfloat4 a) +{ + return vfloat4(vmaxvq_f32(a.m)); +} + +/** + * @brief Return the horizontal sum of a vector. + */ +ASTCENC_SIMD_INLINE float hadd_s(vfloat4 a) +{ + // Perform halving add to ensure invariance; we cannot use vaddqv as this + // does (0 + 1 + 2 + 3) which is not invariant with x86 (0 + 2) + (1 + 3). + float32x2_t t = vadd_f32(vget_high_f32(a.m), vget_low_f32(a.m)); + return vget_lane_f32(vpadd_f32(t, t), 0); +} + +/** + * @brief Return the sqrt of the lanes in the vector. + */ +ASTCENC_SIMD_INLINE vfloat4 sqrt(vfloat4 a) +{ + return vfloat4(vsqrtq_f32(a.m)); +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat4 select(vfloat4 a, vfloat4 b, vmask4 cond) +{ + return vfloat4(vbslq_f32(cond.m, b.m, a.m)); +} + +/** + * @brief Return lanes from @c b if MSB of @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat4 select_msb(vfloat4 a, vfloat4 b, vmask4 cond) +{ + static const uint32x4_t msb = vdupq_n_u32(0x80000000u); + uint32x4_t mask = vcgeq_u32(cond.m, msb); + return vfloat4(vbslq_f32(mask, b.m, a.m)); +} + +/** + * @brief Load a vector of gathered results from an array; + */ +ASTCENC_SIMD_INLINE vfloat4 gatherf(const float* base, vint4 indices) +{ + alignas(16) int idx[4]; + storea(indices, idx); + alignas(16) float vals[4]; + vals[0] = base[idx[0]]; + vals[1] = base[idx[1]]; + vals[2] = base[idx[2]]; + vals[3] = base[idx[3]]; + return vfloat4(vals); +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vfloat4 a, float* p) +{ + vst1q_f32(p, a.m); +} + +/** + * @brief Store a vector to a 16B aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vfloat4 a, float* p) +{ + vst1q_f32(p, a.m); +} + +/** + * @brief Return a integer value for a float vector, using truncation. + */ +ASTCENC_SIMD_INLINE vint4 float_to_int(vfloat4 a) +{ + return vint4(vcvtq_s32_f32(a.m)); +} + +/** + * @brief Return a integer value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint4 float_to_int_rtn(vfloat4 a) +{ + a = round(a); + return vint4(vcvtq_s32_f32(a.m)); +} + +/** + * @brief Return a float value for an integer vector. + */ +ASTCENC_SIMD_INLINE vfloat4 int_to_float(vint4 a) +{ + return vfloat4(vcvtq_f32_s32(a.m)); +} + +/** + * @brief Return a float16 value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint4 float_to_float16(vfloat4 a) +{ + // Generate float16 value + float16x4_t f16 = vcvt_f16_f32(a.m); + + // Convert each 16-bit float pattern to a 32-bit pattern + uint16x4_t u16 = vreinterpret_u16_f16(f16); + uint32x4_t u32 = vmovl_u16(u16); + return vint4(vreinterpretq_s32_u32(u32)); +} + +/** + * @brief Return a float16 value for a float scalar, using round-to-nearest. + */ +static inline uint16_t float_to_float16(float a) +{ + vfloat4 av(a); + return static_cast<uint16_t>(float_to_float16(av).lane<0>()); +} + +/** + * @brief Return a float value for a float16 vector. + */ +ASTCENC_SIMD_INLINE vfloat4 float16_to_float(vint4 a) +{ + // Convert each 32-bit float pattern to a 16-bit pattern + uint32x4_t u32 = vreinterpretq_u32_s32(a.m); + uint16x4_t u16 = vmovn_u32(u32); + float16x4_t f16 = vreinterpret_f16_u16(u16); + + // Generate float16 value + return vfloat4(vcvt_f32_f16(f16)); +} + +/** + * @brief Return a float value for a float16 scalar. + */ +ASTCENC_SIMD_INLINE float float16_to_float(uint16_t a) +{ + vint4 av(a); + return float16_to_float(av).lane<0>(); +} + +/** + * @brief Return a float value as an integer bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the first half of that flip. + */ +ASTCENC_SIMD_INLINE vint4 float_as_int(vfloat4 a) +{ + return vint4(vreinterpretq_s32_f32(a.m)); +} + +/** + * @brief Return a integer value as a float bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the second half of that flip. + */ +ASTCENC_SIMD_INLINE vfloat4 int_as_float(vint4 v) +{ + return vfloat4(vreinterpretq_f32_s32(v.m)); +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p) +{ + t0p = t0; +} + + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p) +{ + t0p = t0; + t1p = t1; +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare( + vint4 t0, vint4 t1, vint4 t2, vint4 t3, + vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p) +{ + t0p = t0; + t1p = t1; + t2p = t2; + t3p = t3; +} + +/** + * @brief Perform an 8-bit 16-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx) +{ + int8x16_t table { + vreinterpretq_s8_s32(t0.m) + }; + + // Set index byte above max index for unused bytes so table lookup returns zero + int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00)); + uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked); + + return vint4(vreinterpretq_s32_s8(vqtbl1q_s8(table, idx_bytes))); +} + +/** + * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx) +{ + int8x16x2_t table { + vreinterpretq_s8_s32(t0.m), + vreinterpretq_s8_s32(t1.m) + }; + + // Set index byte above max index for unused bytes so table lookup returns zero + int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00)); + uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked); + + return vint4(vreinterpretq_s32_s8(vqtbl2q_s8(table, idx_bytes))); +} + +/** + * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx) +{ + int8x16x4_t table { + vreinterpretq_s8_s32(t0.m), + vreinterpretq_s8_s32(t1.m), + vreinterpretq_s8_s32(t2.m), + vreinterpretq_s8_s32(t3.m) + }; + + // Set index byte above max index for unused bytes so table lookup returns zero + int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00)); + uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked); + + return vint4(vreinterpretq_s32_s8(vqtbl4q_s8(table, idx_bytes))); +} + +/** + * @brief Return a vector of interleaved RGBA data. + * + * Input vectors have the value stored in the bottom 8 bits of each lane, + * with high bits set to zero. + * + * Output vector stores a single RGBA texel packed in each lane. + */ +ASTCENC_SIMD_INLINE vint4 interleave_rgba8(vint4 r, vint4 g, vint4 b, vint4 a) +{ + return r + lsl<8>(g) + lsl<16>(b) + lsl<24>(a); +} + +/** + * @brief Store a vector, skipping masked lanes. + * + * All masked lanes must be at the end of vector, after all non-masked lanes. + */ +ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask) +{ + if (mask.lane<3>()) + { + store(data, base); + } + else if (mask.lane<2>()) + { + base[0] = data.lane<0>(); + base[1] = data.lane<1>(); + base[2] = data.lane<2>(); + } + else if (mask.lane<1>()) + { + base[0] = data.lane<0>(); + base[1] = data.lane<1>(); + } + else if (mask.lane<0>()) + { + base[0] = data.lane<0>(); + } +} + +#define ASTCENC_USE_NATIVE_POPCOUNT 1 + +/** + * @brief Population bit count. + * + * @param v The value to population count. + * + * @return The number of 1 bits. + */ +ASTCENC_SIMD_INLINE int popcount(uint64_t v) +{ + return static_cast<int>(vaddlv_u8(vcnt_u8(vcreate_u8(v)))); +} + +#endif // #ifndef ASTC_VECMATHLIB_NEON_4_H_INCLUDED diff --git a/thirdparty/astcenc/astcenc_vecmathlib_none_4.h b/thirdparty/astcenc/astcenc_vecmathlib_none_4.h new file mode 100644 index 0000000000..d9b52be3e4 --- /dev/null +++ b/thirdparty/astcenc/astcenc_vecmathlib_none_4.h @@ -0,0 +1,1169 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2019-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief 4x32-bit vectors, implemented using plain C++. + * + * This module implements 4-wide 32-bit float, int, and mask vectors. This + * module provides a scalar fallback for VLA code, primarily useful for + * debugging VLA algorithms without the complexity of handling SIMD. Only the + * baseline level of functionality needed to support VLA is provided. + * + * Note that the vector conditional operators implemented by this module are + * designed to behave like SIMD conditional operators that generate lane masks. + * Rather than returning 0/1 booleans like normal C++ code they will return + * 0/-1 to give a full lane-width bitmask. + * + * Note that the documentation for this module still talks about "vectors" to + * help developers think about the implied VLA behavior when writing optimized + * paths. + */ + +#ifndef ASTC_VECMATHLIB_NONE_4_H_INCLUDED +#define ASTC_VECMATHLIB_NONE_4_H_INCLUDED + +#ifndef ASTCENC_SIMD_INLINE + #error "Include astcenc_vecmathlib.h, do not include directly" +#endif + +#include <algorithm> +#include <cstdio> +#include <cstring> +#include <cfenv> + +// ============================================================================ +// vfloat4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide floats. + */ +struct vfloat4 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vfloat4() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using loada() which is better with wider VLA vectors if data is + * aligned to vector length. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(const float* p) + { + m[0] = p[0]; + m[1] = p[1]; + m[2] = p[2]; + m[3] = p[3]; + } + + /** + * @brief Construct from 4 scalar values replicated across all lanes. + * + * Consider using zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float a) + { + m[0] = a; + m[1] = a; + m[2] = a; + m[3] = a; + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float a, float b, float c, float d) + { + m[0] = a; + m[1] = b; + m[2] = c; + m[3] = d; + } + + /** + * @brief Get the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE float lane() const + { + return m[l]; + } + + /** + * @brief Set the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE void set_lane(float a) + { + m[l] = a; + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vfloat4 zero() + { + return vfloat4(0.0f); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p) + { + return vfloat4(*p); + } + + /** + * @brief Factory that returns a vector loaded from aligned memory. + */ + static ASTCENC_SIMD_INLINE vfloat4 loada(const float* p) + { + return vfloat4(p); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vfloat4 lane_id() + { + return vfloat4(0.0f, 1.0f, 2.0f, 3.0f); + } + + /** + * @brief Return a swizzled float 2. + */ + template <int l0, int l1> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(lane<l0>(), lane<l1>(), 0.0f, 0.0f); + } + + /** + * @brief Return a swizzled float 3. + */ + template <int l0, int l1, int l2> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), 0.0f); + } + + /** + * @brief Return a swizzled float 4. + */ + template <int l0, int l1, int l2, int l3> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), lane<l3>()); + } + + /** + * @brief The vector ... + */ + float m[4]; +}; + +// ============================================================================ +// vint4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide ints. + */ +struct vint4 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vint4() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using vint4::loada() which is better with wider VLA vectors + * if data is aligned. + */ + ASTCENC_SIMD_INLINE explicit vint4(const int* p) + { + m[0] = p[0]; + m[1] = p[1]; + m[2] = p[2]; + m[3] = p[3]; + } + + /** + * @brief Construct from 4 uint8_t loaded from an unaligned address. + */ + ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p) + { + m[0] = p[0]; + m[1] = p[1]; + m[2] = p[2]; + m[3] = p[3]; + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint4(int a, int b, int c, int d) + { + m[0] = a; + m[1] = b; + m[2] = c; + m[3] = d; + } + + + /** + * @brief Construct from 4 scalar values replicated across all lanes. + * + * Consider using vint4::zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vint4(int a) + { + m[0] = a; + m[1] = a; + m[2] = a; + m[3] = a; + } + + /** + * @brief Get the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE int lane() const + { + return m[l]; + } + + /** + * @brief Set the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE void set_lane(int a) + { + m[l] = a; + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vint4 zero() + { + return vint4(0); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vint4 load1(const int* p) + { + return vint4(*p); + } + + /** + * @brief Factory that returns a vector loaded from 16B aligned memory. + */ + static ASTCENC_SIMD_INLINE vint4 loada(const int* p) + { + return vint4(p); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vint4 lane_id() + { + return vint4(0, 1, 2, 3); + } + + /** + * @brief The vector ... + */ + int m[4]; +}; + +// ============================================================================ +// vmask4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide control plane masks. + */ +struct vmask4 +{ + /** + * @brief Construct from an existing mask value. + */ + ASTCENC_SIMD_INLINE explicit vmask4(int* p) + { + m[0] = p[0]; + m[1] = p[1]; + m[2] = p[2]; + m[3] = p[3]; + } + + /** + * @brief Construct from 1 scalar value. + */ + ASTCENC_SIMD_INLINE explicit vmask4(bool a) + { + m[0] = a == false ? 0 : -1; + m[1] = a == false ? 0 : -1; + m[2] = a == false ? 0 : -1; + m[3] = a == false ? 0 : -1; + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(bool a, bool b, bool c, bool d) + { + m[0] = a == false ? 0 : -1; + m[1] = b == false ? 0 : -1; + m[2] = c == false ? 0 : -1; + m[3] = d == false ? 0 : -1; + } + + + /** + * @brief The vector ... + */ + int m[4]; +}; + +// ============================================================================ +// vmask4 operators and functions +// ============================================================================ + +/** + * @brief Overload: mask union (or). + */ +ASTCENC_SIMD_INLINE vmask4 operator|(vmask4 a, vmask4 b) +{ + return vmask4(a.m[0] | b.m[0], + a.m[1] | b.m[1], + a.m[2] | b.m[2], + a.m[3] | b.m[3]); +} + +/** + * @brief Overload: mask intersect (and). + */ +ASTCENC_SIMD_INLINE vmask4 operator&(vmask4 a, vmask4 b) +{ + return vmask4(a.m[0] & b.m[0], + a.m[1] & b.m[1], + a.m[2] & b.m[2], + a.m[3] & b.m[3]); +} + +/** + * @brief Overload: mask difference (xor). + */ +ASTCENC_SIMD_INLINE vmask4 operator^(vmask4 a, vmask4 b) +{ + return vmask4(a.m[0] ^ b.m[0], + a.m[1] ^ b.m[1], + a.m[2] ^ b.m[2], + a.m[3] ^ b.m[3]); +} + +/** + * @brief Overload: mask invert (not). + */ +ASTCENC_SIMD_INLINE vmask4 operator~(vmask4 a) +{ + return vmask4(~a.m[0], + ~a.m[1], + ~a.m[2], + ~a.m[3]); +} + +/** + * @brief Return a 1-bit mask code indicating mask status. + * + * bit0 = lane 0 + */ +ASTCENC_SIMD_INLINE unsigned int mask(vmask4 a) +{ + return ((a.m[0] >> 31) & 0x1) | + ((a.m[1] >> 30) & 0x2) | + ((a.m[2] >> 29) & 0x4) | + ((a.m[3] >> 28) & 0x8); +} + +// ============================================================================ +// vint4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, vint4 b) +{ + return vint4(a.m[0] + b.m[0], + a.m[1] + b.m[1], + a.m[2] + b.m[2], + a.m[3] + b.m[3]); +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, vint4 b) +{ + return vint4(a.m[0] - b.m[0], + a.m[1] - b.m[1], + a.m[2] - b.m[2], + a.m[3] - b.m[3]); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, vint4 b) +{ + return vint4(a.m[0] * b.m[0], + a.m[1] * b.m[1], + a.m[2] * b.m[2], + a.m[3] * b.m[3]); +} + +/** + * @brief Overload: vector bit invert. + */ +ASTCENC_SIMD_INLINE vint4 operator~(vint4 a) +{ + return vint4(~a.m[0], + ~a.m[1], + ~a.m[2], + ~a.m[3]); +} + +/** + * @brief Overload: vector by vector bitwise or. + */ +ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, vint4 b) +{ + return vint4(a.m[0] | b.m[0], + a.m[1] | b.m[1], + a.m[2] | b.m[2], + a.m[3] | b.m[3]); +} + +/** + * @brief Overload: vector by vector bitwise and. + */ +ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, vint4 b) +{ + return vint4(a.m[0] & b.m[0], + a.m[1] & b.m[1], + a.m[2] & b.m[2], + a.m[3] & b.m[3]); +} + +/** + * @brief Overload: vector by vector bitwise xor. + */ +ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, vint4 b) +{ + return vint4(a.m[0] ^ b.m[0], + a.m[1] ^ b.m[1], + a.m[2] ^ b.m[2], + a.m[3] ^ b.m[3]); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask4 operator==(vint4 a, vint4 b) +{ + return vmask4(a.m[0] == b.m[0], + a.m[1] == b.m[1], + a.m[2] == b.m[2], + a.m[3] == b.m[3]); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask4 operator!=(vint4 a, vint4 b) +{ + return vmask4(a.m[0] != b.m[0], + a.m[1] != b.m[1], + a.m[2] != b.m[2], + a.m[3] != b.m[3]); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask4 operator<(vint4 a, vint4 b) +{ + return vmask4(a.m[0] < b.m[0], + a.m[1] < b.m[1], + a.m[2] < b.m[2], + a.m[3] < b.m[3]); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask4 operator>(vint4 a, vint4 b) +{ + return vmask4(a.m[0] > b.m[0], + a.m[1] > b.m[1], + a.m[2] > b.m[2], + a.m[3] > b.m[3]); +} + +/** + * @brief Logical shift left. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 lsl(vint4 a) +{ + return vint4(a.m[0] << s, + a.m[1] << s, + a.m[2] << s, + a.m[3] << s); +} + +/** + * @brief Logical shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 lsr(vint4 a) +{ + unsigned int as0 = static_cast<unsigned int>(a.m[0]) >> s; + unsigned int as1 = static_cast<unsigned int>(a.m[1]) >> s; + unsigned int as2 = static_cast<unsigned int>(a.m[2]) >> s; + unsigned int as3 = static_cast<unsigned int>(a.m[3]) >> s; + + return vint4(static_cast<int>(as0), + static_cast<int>(as1), + static_cast<int>(as2), + static_cast<int>(as3)); +} + +/** + * @brief Arithmetic shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 asr(vint4 a) +{ + return vint4(a.m[0] >> s, + a.m[1] >> s, + a.m[2] >> s, + a.m[3] >> s); +} + +/** + * @brief Return the min vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint4 min(vint4 a, vint4 b) +{ + return vint4(a.m[0] < b.m[0] ? a.m[0] : b.m[0], + a.m[1] < b.m[1] ? a.m[1] : b.m[1], + a.m[2] < b.m[2] ? a.m[2] : b.m[2], + a.m[3] < b.m[3] ? a.m[3] : b.m[3]); +} + +/** + * @brief Return the min vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint4 max(vint4 a, vint4 b) +{ + return vint4(a.m[0] > b.m[0] ? a.m[0] : b.m[0], + a.m[1] > b.m[1] ? a.m[1] : b.m[1], + a.m[2] > b.m[2] ? a.m[2] : b.m[2], + a.m[3] > b.m[3] ? a.m[3] : b.m[3]); +} + +/** + * @brief Return the horizontal minimum of a single vector. + */ +ASTCENC_SIMD_INLINE vint4 hmin(vint4 a) +{ + int b = std::min(a.m[0], a.m[1]); + int c = std::min(a.m[2], a.m[3]); + return vint4(std::min(b, c)); +} + +/** + * @brief Return the horizontal maximum of a single vector. + */ +ASTCENC_SIMD_INLINE vint4 hmax(vint4 a) +{ + int b = std::max(a.m[0], a.m[1]); + int c = std::max(a.m[2], a.m[3]); + return vint4(std::max(b, c)); +} + +/** + * @brief Return the horizontal sum of vector lanes as a scalar. + */ +ASTCENC_SIMD_INLINE int hadd_s(vint4 a) +{ + return a.m[0] + a.m[1] + a.m[2] + a.m[3]; +} + +/** + * @brief Store a vector to an aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vint4 a, int* p) +{ + p[0] = a.m[0]; + p[1] = a.m[1]; + p[2] = a.m[2]; + p[3] = a.m[3]; +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vint4 a, int* p) +{ + p[0] = a.m[0]; + p[1] = a.m[1]; + p[2] = a.m[2]; + p[3] = a.m[3]; +} + +/** + * @brief Store lowest N (vector width) bytes into an unaligned address. + */ +ASTCENC_SIMD_INLINE void store_nbytes(vint4 a, uint8_t* p) +{ + int* pi = reinterpret_cast<int*>(p); + *pi = a.m[0]; +} + +/** + * @brief Gather N (vector width) indices from the array. + */ +ASTCENC_SIMD_INLINE vint4 gatheri(const int* base, vint4 indices) +{ + return vint4(base[indices.m[0]], + base[indices.m[1]], + base[indices.m[2]], + base[indices.m[3]]); +} + +/** + * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector. + */ +ASTCENC_SIMD_INLINE vint4 pack_low_bytes(vint4 a) +{ + int b0 = a.m[0] & 0xFF; + int b1 = a.m[1] & 0xFF; + int b2 = a.m[2] & 0xFF; + int b3 = a.m[3] & 0xFF; + + int b = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); + return vint4(b, 0, 0, 0); +} + +/** + * @brief Return lanes from @c b if MSB of @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vint4 select(vint4 a, vint4 b, vmask4 cond) +{ + return vint4((cond.m[0] & static_cast<int>(0x80000000)) ? b.m[0] : a.m[0], + (cond.m[1] & static_cast<int>(0x80000000)) ? b.m[1] : a.m[1], + (cond.m[2] & static_cast<int>(0x80000000)) ? b.m[2] : a.m[2], + (cond.m[3] & static_cast<int>(0x80000000)) ? b.m[3] : a.m[3]); +} + +// ============================================================================ +// vfloat4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, vfloat4 b) +{ + return vfloat4(a.m[0] + b.m[0], + a.m[1] + b.m[1], + a.m[2] + b.m[2], + a.m[3] + b.m[3]); +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, vfloat4 b) +{ + return vfloat4(a.m[0] - b.m[0], + a.m[1] - b.m[1], + a.m[2] - b.m[2], + a.m[3] - b.m[3]); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, vfloat4 b) +{ + return vfloat4(a.m[0] * b.m[0], + a.m[1] * b.m[1], + a.m[2] * b.m[2], + a.m[3] * b.m[3]); +} + +/** + * @brief Overload: vector by vector division. + */ +ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, vfloat4 b) +{ + return vfloat4(a.m[0] / b.m[0], + a.m[1] / b.m[1], + a.m[2] / b.m[2], + a.m[3] / b.m[3]); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask4 operator==(vfloat4 a, vfloat4 b) +{ + return vmask4(a.m[0] == b.m[0], + a.m[1] == b.m[1], + a.m[2] == b.m[2], + a.m[3] == b.m[3]); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask4 operator!=(vfloat4 a, vfloat4 b) +{ + return vmask4(a.m[0] != b.m[0], + a.m[1] != b.m[1], + a.m[2] != b.m[2], + a.m[3] != b.m[3]); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask4 operator<(vfloat4 a, vfloat4 b) +{ + return vmask4(a.m[0] < b.m[0], + a.m[1] < b.m[1], + a.m[2] < b.m[2], + a.m[3] < b.m[3]); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask4 operator>(vfloat4 a, vfloat4 b) +{ + return vmask4(a.m[0] > b.m[0], + a.m[1] > b.m[1], + a.m[2] > b.m[2], + a.m[3] > b.m[3]); +} + +/** + * @brief Overload: vector by vector less than or equal. + */ +ASTCENC_SIMD_INLINE vmask4 operator<=(vfloat4 a, vfloat4 b) +{ + return vmask4(a.m[0] <= b.m[0], + a.m[1] <= b.m[1], + a.m[2] <= b.m[2], + a.m[3] <= b.m[3]); +} + +/** + * @brief Overload: vector by vector greater than or equal. + */ +ASTCENC_SIMD_INLINE vmask4 operator>=(vfloat4 a, vfloat4 b) +{ + return vmask4(a.m[0] >= b.m[0], + a.m[1] >= b.m[1], + a.m[2] >= b.m[2], + a.m[3] >= b.m[3]); +} + +/** + * @brief Return the min vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, vfloat4 b) +{ + return vfloat4(a.m[0] < b.m[0] ? a.m[0] : b.m[0], + a.m[1] < b.m[1] ? a.m[1] : b.m[1], + a.m[2] < b.m[2] ? a.m[2] : b.m[2], + a.m[3] < b.m[3] ? a.m[3] : b.m[3]); +} + +/** + * @brief Return the max vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, vfloat4 b) +{ + return vfloat4(a.m[0] > b.m[0] ? a.m[0] : b.m[0], + a.m[1] > b.m[1] ? a.m[1] : b.m[1], + a.m[2] > b.m[2] ? a.m[2] : b.m[2], + a.m[3] > b.m[3] ? a.m[3] : b.m[3]); +} + +/** + * @brief Return the absolute value of the float vector. + */ +ASTCENC_SIMD_INLINE vfloat4 abs(vfloat4 a) +{ + return vfloat4(std::abs(a.m[0]), + std::abs(a.m[1]), + std::abs(a.m[2]), + std::abs(a.m[3])); +} + +/** + * @brief Return a float rounded to the nearest integer value. + */ +ASTCENC_SIMD_INLINE vfloat4 round(vfloat4 a) +{ + assert(std::fegetround() == FE_TONEAREST); + return vfloat4(std::nearbyint(a.m[0]), + std::nearbyint(a.m[1]), + std::nearbyint(a.m[2]), + std::nearbyint(a.m[3])); +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat4 hmin(vfloat4 a) +{ + float tmp1 = std::min(a.m[0], a.m[1]); + float tmp2 = std::min(a.m[2], a.m[3]); + return vfloat4(std::min(tmp1, tmp2)); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat4 hmax(vfloat4 a) +{ + float tmp1 = std::max(a.m[0], a.m[1]); + float tmp2 = std::max(a.m[2], a.m[3]); + return vfloat4(std::max(tmp1, tmp2)); +} + +/** + * @brief Return the horizontal sum of a vector. + */ +ASTCENC_SIMD_INLINE float hadd_s(vfloat4 a) +{ + // Use halving add, gives invariance with SIMD versions + return (a.m[0] + a.m[2]) + (a.m[1] + a.m[3]); +} + +/** + * @brief Return the sqrt of the lanes in the vector. + */ +ASTCENC_SIMD_INLINE vfloat4 sqrt(vfloat4 a) +{ + return vfloat4(std::sqrt(a.m[0]), + std::sqrt(a.m[1]), + std::sqrt(a.m[2]), + std::sqrt(a.m[3])); +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat4 select(vfloat4 a, vfloat4 b, vmask4 cond) +{ + return vfloat4((cond.m[0] & static_cast<int>(0x80000000)) ? b.m[0] : a.m[0], + (cond.m[1] & static_cast<int>(0x80000000)) ? b.m[1] : a.m[1], + (cond.m[2] & static_cast<int>(0x80000000)) ? b.m[2] : a.m[2], + (cond.m[3] & static_cast<int>(0x80000000)) ? b.m[3] : a.m[3]); +} + +/** + * @brief Return lanes from @c b if MSB of @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat4 select_msb(vfloat4 a, vfloat4 b, vmask4 cond) +{ + return vfloat4((cond.m[0] & static_cast<int>(0x80000000)) ? b.m[0] : a.m[0], + (cond.m[1] & static_cast<int>(0x80000000)) ? b.m[1] : a.m[1], + (cond.m[2] & static_cast<int>(0x80000000)) ? b.m[2] : a.m[2], + (cond.m[3] & static_cast<int>(0x80000000)) ? b.m[3] : a.m[3]); +} + +/** + * @brief Load a vector of gathered results from an array; + */ +ASTCENC_SIMD_INLINE vfloat4 gatherf(const float* base, vint4 indices) +{ + return vfloat4(base[indices.m[0]], + base[indices.m[1]], + base[indices.m[2]], + base[indices.m[3]]); +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vfloat4 a, float* ptr) +{ + ptr[0] = a.m[0]; + ptr[1] = a.m[1]; + ptr[2] = a.m[2]; + ptr[3] = a.m[3]; +} + +/** + * @brief Store a vector to an aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vfloat4 a, float* ptr) +{ + ptr[0] = a.m[0]; + ptr[1] = a.m[1]; + ptr[2] = a.m[2]; + ptr[3] = a.m[3]; +} + +/** + * @brief Return a integer value for a float vector, using truncation. + */ +ASTCENC_SIMD_INLINE vint4 float_to_int(vfloat4 a) +{ + return vint4(static_cast<int>(a.m[0]), + static_cast<int>(a.m[1]), + static_cast<int>(a.m[2]), + static_cast<int>(a.m[3])); +} + +/**f + * @brief Return a integer value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint4 float_to_int_rtn(vfloat4 a) +{ + return vint4(static_cast<int>(a.m[0] + 0.5f), + static_cast<int>(a.m[1] + 0.5f), + static_cast<int>(a.m[2] + 0.5f), + static_cast<int>(a.m[3] + 0.5f)); +} + +/** + * @brief Return a float value for a integer vector. + */ +ASTCENC_SIMD_INLINE vfloat4 int_to_float(vint4 a) +{ + return vfloat4(static_cast<float>(a.m[0]), + static_cast<float>(a.m[1]), + static_cast<float>(a.m[2]), + static_cast<float>(a.m[3])); +} + +/** + * @brief Return a float16 value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint4 float_to_float16(vfloat4 a) +{ + return vint4( + float_to_sf16(a.lane<0>()), + float_to_sf16(a.lane<1>()), + float_to_sf16(a.lane<2>()), + float_to_sf16(a.lane<3>())); +} + +/** + * @brief Return a float16 value for a float scalar, using round-to-nearest. + */ +static inline uint16_t float_to_float16(float a) +{ + return float_to_sf16(a); +} + +/** + * @brief Return a float value for a float16 vector. + */ +ASTCENC_SIMD_INLINE vfloat4 float16_to_float(vint4 a) +{ + return vfloat4( + sf16_to_float(static_cast<uint16_t>(a.lane<0>())), + sf16_to_float(static_cast<uint16_t>(a.lane<1>())), + sf16_to_float(static_cast<uint16_t>(a.lane<2>())), + sf16_to_float(static_cast<uint16_t>(a.lane<3>()))); +} + +/** + * @brief Return a float value for a float16 scalar. + */ +ASTCENC_SIMD_INLINE float float16_to_float(uint16_t a) +{ + return sf16_to_float(a); +} + +/** + * @brief Return a float value as an integer bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the first half of that flip. + */ +ASTCENC_SIMD_INLINE vint4 float_as_int(vfloat4 a) +{ + vint4 r; + memcpy(r.m, a.m, 4 * 4); + return r; +} + +/** + * @brief Return a integer value as a float bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the second half of that flip. + */ +ASTCENC_SIMD_INLINE vfloat4 int_as_float(vint4 a) +{ + vfloat4 r; + memcpy(r.m, a.m, 4 * 4); + return r; +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p) +{ + t0p = t0; +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p) +{ + t0p = t0; + t1p = t1; +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare( + vint4 t0, vint4 t1, vint4 t2, vint4 t3, + vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p) +{ + t0p = t0; + t1p = t1; + t2p = t2; + t3p = t3; +} + +/** + * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx) +{ + uint8_t table[16]; + storea(t0, reinterpret_cast<int*>(table + 0)); + + return vint4(table[idx.lane<0>()], + table[idx.lane<1>()], + table[idx.lane<2>()], + table[idx.lane<3>()]); +} + + +/** + * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx) +{ + uint8_t table[32]; + storea(t0, reinterpret_cast<int*>(table + 0)); + storea(t1, reinterpret_cast<int*>(table + 16)); + + return vint4(table[idx.lane<0>()], + table[idx.lane<1>()], + table[idx.lane<2>()], + table[idx.lane<3>()]); +} + +/** + * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx) +{ + uint8_t table[64]; + storea(t0, reinterpret_cast<int*>(table + 0)); + storea(t1, reinterpret_cast<int*>(table + 16)); + storea(t2, reinterpret_cast<int*>(table + 32)); + storea(t3, reinterpret_cast<int*>(table + 48)); + + return vint4(table[idx.lane<0>()], + table[idx.lane<1>()], + table[idx.lane<2>()], + table[idx.lane<3>()]); +} + +/** + * @brief Return a vector of interleaved RGBA data. + * + * Input vectors have the value stored in the bottom 8 bits of each lane, + * with high bits set to zero. + * + * Output vector stores a single RGBA texel packed in each lane. + */ +ASTCENC_SIMD_INLINE vint4 interleave_rgba8(vint4 r, vint4 g, vint4 b, vint4 a) +{ + return r + lsl<8>(g) + lsl<16>(b) + lsl<24>(a); +} + +/** + * @brief Store a vector, skipping masked lanes. + * + * All masked lanes must be at the end of vector, after all non-masked lanes. + */ +ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask) +{ + if (mask.m[3]) + { + store(data, base); + } + else if (mask.m[2]) + { + base[0] = data.lane<0>(); + base[1] = data.lane<1>(); + base[2] = data.lane<2>(); + } + else if (mask.m[1]) + { + base[0] = data.lane<0>(); + base[1] = data.lane<1>(); + } + else if (mask.m[0]) + { + base[0] = data.lane<0>(); + } +} + +#endif // #ifndef ASTC_VECMATHLIB_NONE_4_H_INCLUDED diff --git a/thirdparty/astcenc/astcenc_vecmathlib_sse_4.h b/thirdparty/astcenc/astcenc_vecmathlib_sse_4.h new file mode 100644 index 0000000000..26dcc4a891 --- /dev/null +++ b/thirdparty/astcenc/astcenc_vecmathlib_sse_4.h @@ -0,0 +1,1283 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2019-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief 4x32-bit vectors, implemented using SSE. + * + * This module implements 4-wide 32-bit float, int, and mask vectors for x86 + * SSE. The implementation requires at least SSE2, but higher levels of SSE can + * be selected at compile time to improve performance. + * + * There is a baseline level of functionality provided by all vector widths and + * implementations. This is implemented using identical function signatures, + * modulo data type, so we can use them as substitutable implementations in VLA + * code. + * + * The 4-wide vectors are also used as a fixed-width type, and significantly + * extend the functionality above that available to VLA code. + */ + +#ifndef ASTC_VECMATHLIB_SSE_4_H_INCLUDED +#define ASTC_VECMATHLIB_SSE_4_H_INCLUDED + +#ifndef ASTCENC_SIMD_INLINE + #error "Include astcenc_vecmathlib.h, do not include directly" +#endif + +#include <cstdio> + +// ============================================================================ +// vfloat4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide floats. + */ +struct vfloat4 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vfloat4() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using loada() which is better with vectors if data is aligned + * to vector length. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(const float *p) + { + m = _mm_loadu_ps(p); + } + + /** + * @brief Construct from 1 scalar value replicated across all lanes. + * + * Consider using zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float a) + { + m = _mm_set1_ps(a); + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(float a, float b, float c, float d) + { + m = _mm_set_ps(d, c, b, a); + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vfloat4(__m128 a) + { + m = a; + } + + /** + * @brief Get the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE float lane() const + { + return _mm_cvtss_f32(_mm_shuffle_ps(m, m, l)); + } + + /** + * @brief Set the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE void set_lane(float a) + { +#if ASTCENC_SSE >= 41 + __m128 v = _mm_set1_ps(a); + m = _mm_insert_ps(m, v, l << 6 | l << 4); +#else + alignas(16) float idx[4]; + _mm_store_ps(idx, m); + idx[l] = a; + m = _mm_load_ps(idx); +#endif + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vfloat4 zero() + { + return vfloat4(_mm_setzero_ps()); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p) + { + return vfloat4(_mm_load_ps1(p)); + } + + /** + * @brief Factory that returns a vector loaded from 16B aligned memory. + */ + static ASTCENC_SIMD_INLINE vfloat4 loada(const float* p) + { + return vfloat4(_mm_load_ps(p)); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vfloat4 lane_id() + { + return vfloat4(_mm_set_ps(3, 2, 1, 0)); + } + + /** + * @brief Return a swizzled float 2. + */ + template <int l0, int l1> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + vfloat4 result(_mm_shuffle_ps(m, m, l0 | l1 << 2)); + result.set_lane<2>(0.0f); + result.set_lane<3>(0.0f); + return result; + } + + /** + * @brief Return a swizzled float 3. + */ + template <int l0, int l1, int l2> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + vfloat4 result(_mm_shuffle_ps(m, m, l0 | l1 << 2 | l2 << 4)); + result.set_lane<3>(0.0f); + return result; + } + + /** + * @brief Return a swizzled float 4. + */ + template <int l0, int l1, int l2, int l3> ASTCENC_SIMD_INLINE vfloat4 swz() const + { + return vfloat4(_mm_shuffle_ps(m, m, l0 | l1 << 2 | l2 << 4 | l3 << 6)); + } + + /** + * @brief The vector ... + */ + __m128 m; +}; + +// ============================================================================ +// vint4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide ints. + */ +struct vint4 +{ + /** + * @brief Construct from zero-initialized value. + */ + ASTCENC_SIMD_INLINE vint4() = default; + + /** + * @brief Construct from 4 values loaded from an unaligned address. + * + * Consider using loada() which is better with vectors if data is aligned + * to vector length. + */ + ASTCENC_SIMD_INLINE explicit vint4(const int *p) + { + m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p)); + } + + /** + * @brief Construct from 4 uint8_t loaded from an unaligned address. + */ + ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p) + { + // _mm_loadu_si32 would be nicer syntax, but missing on older GCC + __m128i t = _mm_cvtsi32_si128(*reinterpret_cast<const int*>(p)); + +#if ASTCENC_SSE >= 41 + m = _mm_cvtepu8_epi32(t); +#else + t = _mm_unpacklo_epi8(t, _mm_setzero_si128()); + m = _mm_unpacklo_epi16(t, _mm_setzero_si128()); +#endif + } + + /** + * @brief Construct from 1 scalar value replicated across all lanes. + * + * Consider using vfloat4::zero() for constexpr zeros. + */ + ASTCENC_SIMD_INLINE explicit vint4(int a) + { + m = _mm_set1_epi32(a); + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint4(int a, int b, int c, int d) + { + m = _mm_set_epi32(d, c, b, a); + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vint4(__m128i a) + { + m = a; + } + + /** + * @brief Get the scalar from a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE int lane() const + { + return _mm_cvtsi128_si32(_mm_shuffle_epi32(m, l)); + } + + /** + * @brief Set the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE void set_lane(int a) + { +#if ASTCENC_SSE >= 41 + m = _mm_insert_epi32(m, a, l); +#else + alignas(16) int idx[4]; + _mm_store_si128(reinterpret_cast<__m128i*>(idx), m); + idx[l] = a; + m = _mm_load_si128(reinterpret_cast<const __m128i*>(idx)); +#endif + } + + /** + * @brief Factory that returns a vector of zeros. + */ + static ASTCENC_SIMD_INLINE vint4 zero() + { + return vint4(_mm_setzero_si128()); + } + + /** + * @brief Factory that returns a replicated scalar loaded from memory. + */ + static ASTCENC_SIMD_INLINE vint4 load1(const int* p) + { + return vint4(*p); + } + + /** + * @brief Factory that returns a vector loaded from 16B aligned memory. + */ + static ASTCENC_SIMD_INLINE vint4 loada(const int* p) + { + return vint4(_mm_load_si128(reinterpret_cast<const __m128i*>(p))); + } + + /** + * @brief Factory that returns a vector containing the lane IDs. + */ + static ASTCENC_SIMD_INLINE vint4 lane_id() + { + return vint4(_mm_set_epi32(3, 2, 1, 0)); + } + + /** + * @brief The vector ... + */ + __m128i m; +}; + +// ============================================================================ +// vmask4 data type +// ============================================================================ + +/** + * @brief Data type for 4-wide control plane masks. + */ +struct vmask4 +{ + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(__m128 a) + { + m = a; + } + + /** + * @brief Construct from an existing SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(__m128i a) + { + m = _mm_castsi128_ps(a); + } + + /** + * @brief Construct from 1 scalar value. + */ + ASTCENC_SIMD_INLINE explicit vmask4(bool a) + { + vint4 mask(a == false ? 0 : -1); + m = _mm_castsi128_ps(mask.m); + } + + /** + * @brief Construct from 4 scalar values. + * + * The value of @c a is stored to lane 0 (LSB) in the SIMD register. + */ + ASTCENC_SIMD_INLINE explicit vmask4(bool a, bool b, bool c, bool d) + { + vint4 mask(a == false ? 0 : -1, + b == false ? 0 : -1, + c == false ? 0 : -1, + d == false ? 0 : -1); + + m = _mm_castsi128_ps(mask.m); + } + + /** + * @brief Get the scalar value of a single lane. + */ + template <int l> ASTCENC_SIMD_INLINE float lane() const + { + return _mm_cvtss_f32(_mm_shuffle_ps(m, m, l)); + } + + /** + * @brief The vector ... + */ + __m128 m; +}; + +// ============================================================================ +// vmask4 operators and functions +// ============================================================================ + +/** + * @brief Overload: mask union (or). + */ +ASTCENC_SIMD_INLINE vmask4 operator|(vmask4 a, vmask4 b) +{ + return vmask4(_mm_or_ps(a.m, b.m)); +} + +/** + * @brief Overload: mask intersect (and). + */ +ASTCENC_SIMD_INLINE vmask4 operator&(vmask4 a, vmask4 b) +{ + return vmask4(_mm_and_ps(a.m, b.m)); +} + +/** + * @brief Overload: mask difference (xor). + */ +ASTCENC_SIMD_INLINE vmask4 operator^(vmask4 a, vmask4 b) +{ + return vmask4(_mm_xor_ps(a.m, b.m)); +} + +/** + * @brief Overload: mask invert (not). + */ +ASTCENC_SIMD_INLINE vmask4 operator~(vmask4 a) +{ + return vmask4(_mm_xor_si128(_mm_castps_si128(a.m), _mm_set1_epi32(-1))); +} + +/** + * @brief Return a 4-bit mask code indicating mask status. + * + * bit0 = lane 0 + */ +ASTCENC_SIMD_INLINE unsigned int mask(vmask4 a) +{ + return static_cast<unsigned int>(_mm_movemask_ps(a.m)); +} + +// ============================================================================ +// vint4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, vint4 b) +{ + return vint4(_mm_add_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, vint4 b) +{ + return vint4(_mm_sub_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, vint4 b) +{ +#if ASTCENC_SSE >= 41 + return vint4(_mm_mullo_epi32 (a.m, b.m)); +#else + __m128i t1 = _mm_mul_epu32(a.m, b.m); + __m128i t2 = _mm_mul_epu32( + _mm_srli_si128(a.m, 4), + _mm_srli_si128(b.m, 4)); + __m128i r = _mm_unpacklo_epi32( + _mm_shuffle_epi32(t1, _MM_SHUFFLE (0, 0, 2, 0)), + _mm_shuffle_epi32(t2, _MM_SHUFFLE (0, 0, 2, 0))); + return vint4(r); +#endif +} + +/** + * @brief Overload: vector bit invert. + */ +ASTCENC_SIMD_INLINE vint4 operator~(vint4 a) +{ + return vint4(_mm_xor_si128(a.m, _mm_set1_epi32(-1))); +} + +/** + * @brief Overload: vector by vector bitwise or. + */ +ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, vint4 b) +{ + return vint4(_mm_or_si128(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector bitwise and. + */ +ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, vint4 b) +{ + return vint4(_mm_and_si128(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector bitwise xor. + */ +ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, vint4 b) +{ + return vint4(_mm_xor_si128(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask4 operator==(vint4 a, vint4 b) +{ + return vmask4(_mm_cmpeq_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask4 operator!=(vint4 a, vint4 b) +{ + return ~vmask4(_mm_cmpeq_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask4 operator<(vint4 a, vint4 b) +{ + return vmask4(_mm_cmplt_epi32(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask4 operator>(vint4 a, vint4 b) +{ + return vmask4(_mm_cmpgt_epi32(a.m, b.m)); +} + +/** + * @brief Logical shift left. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 lsl(vint4 a) +{ + return vint4(_mm_slli_epi32(a.m, s)); +} + +/** + * @brief Logical shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 lsr(vint4 a) +{ + return vint4(_mm_srli_epi32(a.m, s)); +} + +/** + * @brief Arithmetic shift right. + */ +template <int s> ASTCENC_SIMD_INLINE vint4 asr(vint4 a) +{ + return vint4(_mm_srai_epi32(a.m, s)); +} + +/** + * @brief Return the min vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint4 min(vint4 a, vint4 b) +{ +#if ASTCENC_SSE >= 41 + return vint4(_mm_min_epi32(a.m, b.m)); +#else + vmask4 d = a < b; + __m128i ap = _mm_and_si128(_mm_castps_si128(d.m), a.m); + __m128i bp = _mm_andnot_si128(_mm_castps_si128(d.m), b.m); + return vint4(_mm_or_si128(ap,bp)); +#endif +} + +/** + * @brief Return the max vector of two vectors. + */ +ASTCENC_SIMD_INLINE vint4 max(vint4 a, vint4 b) +{ +#if ASTCENC_SSE >= 41 + return vint4(_mm_max_epi32(a.m, b.m)); +#else + vmask4 d = a > b; + __m128i ap = _mm_and_si128(_mm_castps_si128(d.m), a.m); + __m128i bp = _mm_andnot_si128(_mm_castps_si128(d.m), b.m); + return vint4(_mm_or_si128(ap,bp)); +#endif +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vint4 hmin(vint4 a) +{ + a = min(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 3, 2)))); + a = min(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 1)))); + return vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 0))); +} + +/* + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vint4 hmax(vint4 a) +{ + a = max(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 3, 2)))); + a = max(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 1)))); + return vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 0))); +} + +/** + * @brief Return the horizontal sum of a vector as a scalar. + */ +ASTCENC_SIMD_INLINE int hadd_s(vint4 a) +{ + // Add top and bottom halves, lane 1/0 + __m128i fold = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(a.m), + _mm_castsi128_ps(a.m))); + __m128i t = _mm_add_epi32(a.m, fold); + + // Add top and bottom halves, lane 0 (_mm_hadd_ps exists but slow) + t = _mm_add_epi32(t, _mm_shuffle_epi32(t, 0x55)); + + return _mm_cvtsi128_si32(t); +} + +/** + * @brief Store a vector to a 16B aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vint4 a, int* p) +{ + _mm_store_si128(reinterpret_cast<__m128i*>(p), a.m); +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vint4 a, int* p) +{ + // Cast due to missing intrinsics + _mm_storeu_ps(reinterpret_cast<float*>(p), _mm_castsi128_ps(a.m)); +} + +/** + * @brief Store lowest N (vector width) bytes into an unaligned address. + */ +ASTCENC_SIMD_INLINE void store_nbytes(vint4 a, uint8_t* p) +{ + // Cast due to missing intrinsics + _mm_store_ss(reinterpret_cast<float*>(p), _mm_castsi128_ps(a.m)); +} + +/** + * @brief Gather N (vector width) indices from the array. + */ +ASTCENC_SIMD_INLINE vint4 gatheri(const int* base, vint4 indices) +{ +#if ASTCENC_AVX >= 2 + return vint4(_mm_i32gather_epi32(base, indices.m, 4)); +#else + alignas(16) int idx[4]; + storea(indices, idx); + return vint4(base[idx[0]], base[idx[1]], base[idx[2]], base[idx[3]]); +#endif +} + +/** + * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector. + */ +ASTCENC_SIMD_INLINE vint4 pack_low_bytes(vint4 a) +{ +#if ASTCENC_SSE >= 41 + __m128i shuf = _mm_set_epi8(0,0,0,0, 0,0,0,0, 0,0,0,0, 12,8,4,0); + return vint4(_mm_shuffle_epi8(a.m, shuf)); +#else + __m128i va = _mm_unpacklo_epi8(a.m, _mm_shuffle_epi32(a.m, _MM_SHUFFLE(1,1,1,1))); + __m128i vb = _mm_unpackhi_epi8(a.m, _mm_shuffle_epi32(a.m, _MM_SHUFFLE(3,3,3,3))); + return vint4(_mm_unpacklo_epi16(va, vb)); +#endif +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vint4 select(vint4 a, vint4 b, vmask4 cond) +{ + __m128i condi = _mm_castps_si128(cond.m); + +#if ASTCENC_SSE >= 41 + return vint4(_mm_blendv_epi8(a.m, b.m, condi)); +#else + return vint4(_mm_or_si128(_mm_and_si128(condi, b.m), _mm_andnot_si128(condi, a.m))); +#endif +} + +// ============================================================================ +// vfloat4 operators and functions +// ============================================================================ + +/** + * @brief Overload: vector by vector addition. + */ +ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, vfloat4 b) +{ + return vfloat4(_mm_add_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector subtraction. + */ +ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, vfloat4 b) +{ + return vfloat4(_mm_sub_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector multiplication. + */ +ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, vfloat4 b) +{ + return vfloat4(_mm_mul_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector division. + */ +ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, vfloat4 b) +{ + return vfloat4(_mm_div_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector equality. + */ +ASTCENC_SIMD_INLINE vmask4 operator==(vfloat4 a, vfloat4 b) +{ + return vmask4(_mm_cmpeq_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector inequality. + */ +ASTCENC_SIMD_INLINE vmask4 operator!=(vfloat4 a, vfloat4 b) +{ + return vmask4(_mm_cmpneq_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector less than. + */ +ASTCENC_SIMD_INLINE vmask4 operator<(vfloat4 a, vfloat4 b) +{ + return vmask4(_mm_cmplt_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector greater than. + */ +ASTCENC_SIMD_INLINE vmask4 operator>(vfloat4 a, vfloat4 b) +{ + return vmask4(_mm_cmpgt_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector less than or equal. + */ +ASTCENC_SIMD_INLINE vmask4 operator<=(vfloat4 a, vfloat4 b) +{ + return vmask4(_mm_cmple_ps(a.m, b.m)); +} + +/** + * @brief Overload: vector by vector greater than or equal. + */ +ASTCENC_SIMD_INLINE vmask4 operator>=(vfloat4 a, vfloat4 b) +{ + return vmask4(_mm_cmpge_ps(a.m, b.m)); +} + +/** + * @brief Return the min vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, vfloat4 b) +{ + // Do not reorder - second operand will return if either is NaN + return vfloat4(_mm_min_ps(a.m, b.m)); +} + +/** + * @brief Return the max vector of two vectors. + * + * If either lane value is NaN, @c b will be returned for that lane. + */ +ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, vfloat4 b) +{ + // Do not reorder - second operand will return if either is NaN + return vfloat4(_mm_max_ps(a.m, b.m)); +} + +/** + * @brief Return the absolute value of the float vector. + */ +ASTCENC_SIMD_INLINE vfloat4 abs(vfloat4 a) +{ + return vfloat4(_mm_max_ps(_mm_sub_ps(_mm_setzero_ps(), a.m), a.m)); +} + +/** + * @brief Return a float rounded to the nearest integer value. + */ +ASTCENC_SIMD_INLINE vfloat4 round(vfloat4 a) +{ +#if ASTCENC_SSE >= 41 + constexpr int flags = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC; + return vfloat4(_mm_round_ps(a.m, flags)); +#else + __m128 v = a.m; + __m128 neg_zero = _mm_castsi128_ps(_mm_set1_epi32(static_cast<int>(0x80000000))); + __m128 no_fraction = _mm_set1_ps(8388608.0f); + __m128 abs_mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF)); + __m128 sign = _mm_and_ps(v, neg_zero); + __m128 s_magic = _mm_or_ps(no_fraction, sign); + __m128 r1 = _mm_add_ps(v, s_magic); + r1 = _mm_sub_ps(r1, s_magic); + __m128 r2 = _mm_and_ps(v, abs_mask); + __m128 mask = _mm_cmple_ps(r2, no_fraction); + r2 = _mm_andnot_ps(mask, v); + r1 = _mm_and_ps(r1, mask); + return vfloat4(_mm_xor_ps(r1, r2)); +#endif +} + +/** + * @brief Return the horizontal minimum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat4 hmin(vfloat4 a) +{ + a = min(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 3, 2)))); + a = min(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 1)))); + return vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 0))); +} + +/** + * @brief Return the horizontal maximum of a vector. + */ +ASTCENC_SIMD_INLINE vfloat4 hmax(vfloat4 a) +{ + a = max(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 3, 2)))); + a = max(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 1)))); + return vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 0))); +} + +/** + * @brief Return the horizontal sum of a vector as a scalar. + */ +ASTCENC_SIMD_INLINE float hadd_s(vfloat4 a) +{ + // Add top and bottom halves, lane 1/0 + __m128 t = _mm_add_ps(a.m, _mm_movehl_ps(a.m, a.m)); + + // Add top and bottom halves, lane 0 (_mm_hadd_ps exists but slow) + t = _mm_add_ss(t, _mm_shuffle_ps(t, t, 0x55)); + + return _mm_cvtss_f32(t); +} + +/** + * @brief Return the sqrt of the lanes in the vector. + */ +ASTCENC_SIMD_INLINE vfloat4 sqrt(vfloat4 a) +{ + return vfloat4(_mm_sqrt_ps(a.m)); +} + +/** + * @brief Return lanes from @c b if @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat4 select(vfloat4 a, vfloat4 b, vmask4 cond) +{ +#if ASTCENC_SSE >= 41 + return vfloat4(_mm_blendv_ps(a.m, b.m, cond.m)); +#else + return vfloat4(_mm_or_ps(_mm_and_ps(cond.m, b.m), _mm_andnot_ps(cond.m, a.m))); +#endif +} + +/** + * @brief Return lanes from @c b if MSB of @c cond is set, else @c a. + */ +ASTCENC_SIMD_INLINE vfloat4 select_msb(vfloat4 a, vfloat4 b, vmask4 cond) +{ +#if ASTCENC_SSE >= 41 + return vfloat4(_mm_blendv_ps(a.m, b.m, cond.m)); +#else + __m128 d = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(cond.m), 31)); + return vfloat4(_mm_or_ps(_mm_and_ps(d, b.m), _mm_andnot_ps(d, a.m))); +#endif +} + +/** + * @brief Load a vector of gathered results from an array; + */ +ASTCENC_SIMD_INLINE vfloat4 gatherf(const float* base, vint4 indices) +{ +#if ASTCENC_AVX >= 2 + return vfloat4(_mm_i32gather_ps(base, indices.m, 4)); +#else + alignas(16) int idx[4]; + storea(indices, idx); + return vfloat4(base[idx[0]], base[idx[1]], base[idx[2]], base[idx[3]]); +#endif +} + +/** + * @brief Store a vector to an unaligned memory address. + */ +ASTCENC_SIMD_INLINE void store(vfloat4 a, float* p) +{ + _mm_storeu_ps(p, a.m); +} + +/** + * @brief Store a vector to a 16B aligned memory address. + */ +ASTCENC_SIMD_INLINE void storea(vfloat4 a, float* p) +{ + _mm_store_ps(p, a.m); +} + +/** + * @brief Return a integer value for a float vector, using truncation. + */ +ASTCENC_SIMD_INLINE vint4 float_to_int(vfloat4 a) +{ + return vint4(_mm_cvttps_epi32(a.m)); +} + +/** + * @brief Return a integer value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint4 float_to_int_rtn(vfloat4 a) +{ + a = round(a); + return vint4(_mm_cvttps_epi32(a.m)); +} + +/** + * @brief Return a float value for an integer vector. + */ +ASTCENC_SIMD_INLINE vfloat4 int_to_float(vint4 a) +{ + return vfloat4(_mm_cvtepi32_ps(a.m)); +} + +/** + * @brief Return a float16 value for a float vector, using round-to-nearest. + */ +ASTCENC_SIMD_INLINE vint4 float_to_float16(vfloat4 a) +{ +#if ASTCENC_F16C >= 1 + __m128i packedf16 = _mm_cvtps_ph(a.m, 0); + __m128i f16 = _mm_cvtepu16_epi32(packedf16); + return vint4(f16); +#else + return vint4( + float_to_sf16(a.lane<0>()), + float_to_sf16(a.lane<1>()), + float_to_sf16(a.lane<2>()), + float_to_sf16(a.lane<3>())); +#endif +} + +/** + * @brief Return a float16 value for a float scalar, using round-to-nearest. + */ +static inline uint16_t float_to_float16(float a) +{ +#if ASTCENC_F16C >= 1 + __m128i f16 = _mm_cvtps_ph(_mm_set1_ps(a), 0); + return static_cast<uint16_t>(_mm_cvtsi128_si32(f16)); +#else + return float_to_sf16(a); +#endif +} + +/** + * @brief Return a float value for a float16 vector. + */ +ASTCENC_SIMD_INLINE vfloat4 float16_to_float(vint4 a) +{ +#if ASTCENC_F16C >= 1 + __m128i packed = _mm_packs_epi32(a.m, a.m); + __m128 f32 = _mm_cvtph_ps(packed); + return vfloat4(f32); +#else + return vfloat4( + sf16_to_float(static_cast<uint16_t>(a.lane<0>())), + sf16_to_float(static_cast<uint16_t>(a.lane<1>())), + sf16_to_float(static_cast<uint16_t>(a.lane<2>())), + sf16_to_float(static_cast<uint16_t>(a.lane<3>()))); +#endif +} + +/** + * @brief Return a float value for a float16 scalar. + */ +ASTCENC_SIMD_INLINE float float16_to_float(uint16_t a) +{ +#if ASTCENC_F16C >= 1 + __m128i packed = _mm_set1_epi16(static_cast<short>(a)); + __m128 f32 = _mm_cvtph_ps(packed); + return _mm_cvtss_f32(f32); +#else + return sf16_to_float(a); +#endif +} + +/** + * @brief Return a float value as an integer bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the first half of that flip. + */ +ASTCENC_SIMD_INLINE vint4 float_as_int(vfloat4 a) +{ + return vint4(_mm_castps_si128(a.m)); +} + +/** + * @brief Return a integer value as a float bit pattern (i.e. no conversion). + * + * It is a common trick to convert floats into integer bit patterns, perform + * some bit hackery based on knowledge they are IEEE 754 layout, and then + * convert them back again. This is the second half of that flip. + */ +ASTCENC_SIMD_INLINE vfloat4 int_as_float(vint4 v) +{ + return vfloat4(_mm_castsi128_ps(v.m)); +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p) +{ + t0p = t0; +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p) +{ +#if ASTCENC_SSE >= 41 + t0p = t0; + t1p = t0 ^ t1; +#else + t0p = t0; + t1p = t1; +#endif +} + +/** + * @brief Prepare a vtable lookup table for use with the native SIMD size. + */ +ASTCENC_SIMD_INLINE void vtable_prepare( + vint4 t0, vint4 t1, vint4 t2, vint4 t3, + vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p) +{ +#if ASTCENC_SSE >= 41 + t0p = t0; + t1p = t0 ^ t1; + t2p = t1 ^ t2; + t3p = t2 ^ t3; +#else + t0p = t0; + t1p = t1; + t2p = t2; + t3p = t3; +#endif +} + +/** + * @brief Perform an 8-bit 16-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx) +{ +#if ASTCENC_SSE >= 41 + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00))); + + __m128i result = _mm_shuffle_epi8(t0.m, idxx); + return vint4(result); +#else + alignas(ASTCENC_VECALIGN) uint8_t table[16]; + storea(t0, reinterpret_cast<int*>(table + 0)); + + return vint4(table[idx.lane<0>()], + table[idx.lane<1>()], + table[idx.lane<2>()], + table[idx.lane<3>()]); +#endif +} + +/** + * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx) +{ +#if ASTCENC_SSE >= 41 + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00))); + + __m128i result = _mm_shuffle_epi8(t0.m, idxx); + idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16)); + + __m128i result2 = _mm_shuffle_epi8(t1.m, idxx); + result = _mm_xor_si128(result, result2); + + return vint4(result); +#else + alignas(ASTCENC_VECALIGN) uint8_t table[32]; + storea(t0, reinterpret_cast<int*>(table + 0)); + storea(t1, reinterpret_cast<int*>(table + 16)); + + return vint4(table[idx.lane<0>()], + table[idx.lane<1>()], + table[idx.lane<2>()], + table[idx.lane<3>()]); +#endif +} + +/** + * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes. + */ +ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx) +{ +#if ASTCENC_SSE >= 41 + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00))); + + __m128i result = _mm_shuffle_epi8(t0.m, idxx); + idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16)); + + __m128i result2 = _mm_shuffle_epi8(t1.m, idxx); + result = _mm_xor_si128(result, result2); + idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16)); + + result2 = _mm_shuffle_epi8(t2.m, idxx); + result = _mm_xor_si128(result, result2); + idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16)); + + result2 = _mm_shuffle_epi8(t3.m, idxx); + result = _mm_xor_si128(result, result2); + + return vint4(result); +#else + alignas(ASTCENC_VECALIGN) uint8_t table[64]; + storea(t0, reinterpret_cast<int*>(table + 0)); + storea(t1, reinterpret_cast<int*>(table + 16)); + storea(t2, reinterpret_cast<int*>(table + 32)); + storea(t3, reinterpret_cast<int*>(table + 48)); + + return vint4(table[idx.lane<0>()], + table[idx.lane<1>()], + table[idx.lane<2>()], + table[idx.lane<3>()]); +#endif +} + +/** + * @brief Return a vector of interleaved RGBA data. + * + * Input vectors have the value stored in the bottom 8 bits of each lane, + * with high bits set to zero. + * + * Output vector stores a single RGBA texel packed in each lane. + */ +ASTCENC_SIMD_INLINE vint4 interleave_rgba8(vint4 r, vint4 g, vint4 b, vint4 a) +{ +// Workaround an XCode compiler internal fault; note is slower than slli_epi32 +// so we should revert this when we get the opportunity +#if defined(__APPLE__) + __m128i value = r.m; + value = _mm_add_epi32(value, _mm_bslli_si128(g.m, 1)); + value = _mm_add_epi32(value, _mm_bslli_si128(b.m, 2)); + value = _mm_add_epi32(value, _mm_bslli_si128(a.m, 3)); + return vint4(value); +#else + __m128i value = r.m; + value = _mm_add_epi32(value, _mm_slli_epi32(g.m, 8)); + value = _mm_add_epi32(value, _mm_slli_epi32(b.m, 16)); + value = _mm_add_epi32(value, _mm_slli_epi32(a.m, 24)); + return vint4(value); +#endif +} + +/** + * @brief Store a vector, skipping masked lanes. + * + * All masked lanes must be at the end of vector, after all non-masked lanes. + */ +ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask) +{ +#if ASTCENC_AVX >= 2 + _mm_maskstore_epi32(base, _mm_castps_si128(mask.m), data.m); +#else + // Note - we cannot use _mm_maskmoveu_si128 as the underlying hardware doesn't guarantee + // fault suppression on masked lanes so we can get page faults at the end of an image. + if (mask.lane<3>() != 0.0f) + { + store(data, base); + } + else if (mask.lane<2>() != 0.0f) + { + base[0] = data.lane<0>(); + base[1] = data.lane<1>(); + base[2] = data.lane<2>(); + } + else if (mask.lane<1>() != 0.0f) + { + base[0] = data.lane<0>(); + base[1] = data.lane<1>(); + } + else if (mask.lane<0>() != 0.0f) + { + base[0] = data.lane<0>(); + } +#endif +} + +#if defined(ASTCENC_NO_INVARIANCE) && (ASTCENC_SSE >= 41) + +#define ASTCENC_USE_NATIVE_DOT_PRODUCT 1 + +/** + * @brief Return the dot product for the full 4 lanes, returning scalar. + */ +ASTCENC_SIMD_INLINE float dot_s(vfloat4 a, vfloat4 b) +{ + return _mm_cvtss_f32(_mm_dp_ps(a.m, b.m, 0xFF)); +} + +/** + * @brief Return the dot product for the full 4 lanes, returning vector. + */ +ASTCENC_SIMD_INLINE vfloat4 dot(vfloat4 a, vfloat4 b) +{ + return vfloat4(_mm_dp_ps(a.m, b.m, 0xFF)); +} + +/** + * @brief Return the dot product for the bottom 3 lanes, returning scalar. + */ +ASTCENC_SIMD_INLINE float dot3_s(vfloat4 a, vfloat4 b) +{ + return _mm_cvtss_f32(_mm_dp_ps(a.m, b.m, 0x77)); +} + +/** + * @brief Return the dot product for the bottom 3 lanes, returning vector. + */ +ASTCENC_SIMD_INLINE vfloat4 dot3(vfloat4 a, vfloat4 b) +{ + return vfloat4(_mm_dp_ps(a.m, b.m, 0x77)); +} + +#endif // #if defined(ASTCENC_NO_INVARIANCE) && (ASTCENC_SSE >= 41) + +#if ASTCENC_POPCNT >= 1 + +#define ASTCENC_USE_NATIVE_POPCOUNT 1 + +/** + * @brief Population bit count. + * + * @param v The value to population count. + * + * @return The number of 1 bits. + */ +ASTCENC_SIMD_INLINE int popcount(uint64_t v) +{ + return static_cast<int>(_mm_popcnt_u64(v)); +} + +#endif // ASTCENC_POPCNT >= 1 + +#endif // #ifndef ASTC_VECMATHLIB_SSE_4_H_INCLUDED diff --git a/thirdparty/astcenc/astcenc_weight_align.cpp b/thirdparty/astcenc/astcenc_weight_align.cpp new file mode 100644 index 0000000000..e40a318cf5 --- /dev/null +++ b/thirdparty/astcenc/astcenc_weight_align.cpp @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2022 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +#if !defined(ASTCENC_DECOMPRESS_ONLY) + +/** + * @brief Functions for angular-sum algorithm for weight alignment. + * + * This algorithm works as follows: + * - we compute a complex number P as (cos s*i, sin s*i) for each weight, + * where i is the input value and s is a scaling factor based on the spacing between the weights. + * - we then add together complex numbers for all the weights. + * - we then compute the length and angle of the resulting sum. + * + * This should produce the following results: + * - perfect alignment results in a vector whose length is equal to the sum of lengths of all inputs + * - even distribution results in a vector of length 0. + * - all samples identical results in perfect alignment for every scaling. + * + * For each scaling factor within a given set, we compute an alignment factor from 0 to 1. This + * should then result in some scalings standing out as having particularly good alignment factors; + * we can use this to produce a set of candidate scale/shift values for various quantization levels; + * we should then actually try them and see what happens. + */ + +#include "astcenc_internal.h" +#include "astcenc_vecmathlib.h" + +#include <stdio.h> +#include <cassert> +#include <cstring> + +static constexpr unsigned int ANGULAR_STEPS { 32 }; + +static_assert((ANGULAR_STEPS % ASTCENC_SIMD_WIDTH) == 0, + "ANGULAR_STEPS must be multiple of ASTCENC_SIMD_WIDTH"); + +static_assert(ANGULAR_STEPS >= 32, + "ANGULAR_STEPS must be at least max(steps_for_quant_level)"); + +// Store a reduced sin/cos table for 64 possible weight values; this causes +// slight quality loss compared to using sin() and cos() directly. Must be 2^N. +static constexpr unsigned int SINCOS_STEPS { 64 }; + +static const uint8_t steps_for_quant_level[12] { + 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32 +}; + +alignas(ASTCENC_VECALIGN) static float sin_table[SINCOS_STEPS][ANGULAR_STEPS]; +alignas(ASTCENC_VECALIGN) static float cos_table[SINCOS_STEPS][ANGULAR_STEPS]; + +#if defined(ASTCENC_DIAGNOSTICS) + static bool print_once { true }; +#endif + +/* See header for documentation. */ +void prepare_angular_tables() +{ + for (unsigned int i = 0; i < ANGULAR_STEPS; i++) + { + float angle_step = static_cast<float>(i + 1); + + for (unsigned int j = 0; j < SINCOS_STEPS; j++) + { + sin_table[j][i] = static_cast<float>(sinf((2.0f * astc::PI / (SINCOS_STEPS - 1.0f)) * angle_step * static_cast<float>(j))); + cos_table[j][i] = static_cast<float>(cosf((2.0f * astc::PI / (SINCOS_STEPS - 1.0f)) * angle_step * static_cast<float>(j))); + } + } +} + +/** + * @brief Compute the angular alignment factors and offsets. + * + * @param weight_count The number of (decimated) weights. + * @param dec_weight_ideal_value The ideal decimated unquantized weight values. + * @param max_angular_steps The maximum number of steps to be tested. + * @param[out] offsets The output angular offsets array. + */ +static void compute_angular_offsets( + unsigned int weight_count, + const float* dec_weight_ideal_value, + unsigned int max_angular_steps, + float* offsets +) { + promise(weight_count > 0); + promise(max_angular_steps > 0); + + alignas(ASTCENC_VECALIGN) int isamplev[BLOCK_MAX_WEIGHTS]; + + // Precompute isample; arrays are always allocated 64 elements long + for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) + { + // Add 2^23 and interpreting bits extracts round-to-nearest int + vfloat sample = loada(dec_weight_ideal_value + i) * (SINCOS_STEPS - 1.0f) + vfloat(12582912.0f); + vint isample = float_as_int(sample) & vint((SINCOS_STEPS - 1)); + storea(isample, isamplev + i); + } + + // Arrays are multiple of SIMD width (ANGULAR_STEPS), safe to overshoot max + vfloat mult = vfloat(1.0f / (2.0f * astc::PI)); + + for (unsigned int i = 0; i < max_angular_steps; i += ASTCENC_SIMD_WIDTH) + { + vfloat anglesum_x = vfloat::zero(); + vfloat anglesum_y = vfloat::zero(); + + for (unsigned int j = 0; j < weight_count; j++) + { + int isample = isamplev[j]; + anglesum_x += loada(cos_table[isample] + i); + anglesum_y += loada(sin_table[isample] + i); + } + + vfloat angle = atan2(anglesum_y, anglesum_x); + vfloat ofs = angle * mult; + storea(ofs, offsets + i); + } +} + +/** + * @brief For a given step size compute the lowest and highest weight. + * + * Compute the lowest and highest weight that results from quantizing using the given stepsize and + * offset, and then compute the resulting error. The cut errors indicate the error that results from + * forcing samples that should have had one weight value one step up or down. + * + * @param weight_count The number of (decimated) weights. + * @param dec_weight_ideal_value The ideal decimated unquantized weight values. + * @param max_angular_steps The maximum number of steps to be tested. + * @param max_quant_steps The maximum quantization level to be tested. + * @param offsets The angular offsets array. + * @param[out] lowest_weight Per angular step, the lowest weight. + * @param[out] weight_span Per angular step, the span between lowest and highest weight. + * @param[out] error Per angular step, the error. + * @param[out] cut_low_weight_error Per angular step, the low weight cut error. + * @param[out] cut_high_weight_error Per angular step, the high weight cut error. + */ +static void compute_lowest_and_highest_weight( + unsigned int weight_count, + const float* dec_weight_ideal_value, + unsigned int max_angular_steps, + unsigned int max_quant_steps, + const float* offsets, + float* lowest_weight, + int* weight_span, + float* error, + float* cut_low_weight_error, + float* cut_high_weight_error +) { + promise(weight_count > 0); + promise(max_angular_steps > 0); + + vfloat rcp_stepsize = vfloat::lane_id() + vfloat(1.0f); + + // Arrays are ANGULAR_STEPS long, so always safe to run full vectors + for (unsigned int sp = 0; sp < max_angular_steps; sp += ASTCENC_SIMD_WIDTH) + { + vfloat minidx(128.0f); + vfloat maxidx(-128.0f); + vfloat errval = vfloat::zero(); + vfloat cut_low_weight_err = vfloat::zero(); + vfloat cut_high_weight_err = vfloat::zero(); + vfloat offset = loada(offsets + sp); + + for (unsigned int j = 0; j < weight_count; j++) + { + vfloat sval = load1(dec_weight_ideal_value + j) * rcp_stepsize - offset; + vfloat svalrte = round(sval); + vfloat diff = sval - svalrte; + errval += diff * diff; + + // Reset tracker on min hit + vmask mask = svalrte < minidx; + minidx = select(minidx, svalrte, mask); + cut_low_weight_err = select(cut_low_weight_err, vfloat::zero(), mask); + + // Accumulate on min hit + mask = svalrte == minidx; + vfloat accum = cut_low_weight_err + vfloat(1.0f) - vfloat(2.0f) * diff; + cut_low_weight_err = select(cut_low_weight_err, accum, mask); + + // Reset tracker on max hit + mask = svalrte > maxidx; + maxidx = select(maxidx, svalrte, mask); + cut_high_weight_err = select(cut_high_weight_err, vfloat::zero(), mask); + + // Accumulate on max hit + mask = svalrte == maxidx; + accum = cut_high_weight_err + vfloat(1.0f) + vfloat(2.0f) * diff; + cut_high_weight_err = select(cut_high_weight_err, accum, mask); + } + + // Write out min weight and weight span; clamp span to a usable range + vint span = float_to_int(maxidx - minidx + vfloat(1)); + span = min(span, vint(max_quant_steps + 3)); + span = max(span, vint(2)); + storea(minidx, lowest_weight + sp); + storea(span, weight_span + sp); + + // The cut_(lowest/highest)_weight_error indicate the error that results from forcing + // samples that should have had the weight value one step (up/down). + vfloat ssize = 1.0f / rcp_stepsize; + vfloat errscale = ssize * ssize; + storea(errval * errscale, error + sp); + storea(cut_low_weight_err * errscale, cut_low_weight_error + sp); + storea(cut_high_weight_err * errscale, cut_high_weight_error + sp); + + rcp_stepsize = rcp_stepsize + vfloat(ASTCENC_SIMD_WIDTH); + } +} + +/** + * @brief The main function for the angular algorithm. + * + * @param weight_count The number of (decimated) weights. + * @param dec_weight_ideal_value The ideal decimated unquantized weight values. + * @param max_quant_level The maximum quantization level to be tested. + * @param[out] low_value Per angular step, the lowest weight value. + * @param[out] high_value Per angular step, the highest weight value. + */ +static void compute_angular_endpoints_for_quant_levels( + unsigned int weight_count, + const float* dec_weight_ideal_value, + unsigned int max_quant_level, + float low_value[TUNE_MAX_ANGULAR_QUANT + 1], + float high_value[TUNE_MAX_ANGULAR_QUANT + 1] +) { + unsigned int max_quant_steps = steps_for_quant_level[max_quant_level]; + unsigned int max_angular_steps = steps_for_quant_level[max_quant_level]; + + alignas(ASTCENC_VECALIGN) float angular_offsets[ANGULAR_STEPS]; + + compute_angular_offsets(weight_count, dec_weight_ideal_value, + max_angular_steps, angular_offsets); + + alignas(ASTCENC_VECALIGN) float lowest_weight[ANGULAR_STEPS]; + alignas(ASTCENC_VECALIGN) int32_t weight_span[ANGULAR_STEPS]; + alignas(ASTCENC_VECALIGN) float error[ANGULAR_STEPS]; + alignas(ASTCENC_VECALIGN) float cut_low_weight_error[ANGULAR_STEPS]; + alignas(ASTCENC_VECALIGN) float cut_high_weight_error[ANGULAR_STEPS]; + + compute_lowest_and_highest_weight(weight_count, dec_weight_ideal_value, + max_angular_steps, max_quant_steps, + angular_offsets, lowest_weight, weight_span, error, + cut_low_weight_error, cut_high_weight_error); + + // For each quantization level, find the best error terms. Use packed vectors so data-dependent + // branches can become selects. This involves some integer to float casts, but the values are + // small enough so they never round the wrong way. + vfloat4 best_results[36]; + + // Initialize the array to some safe defaults + promise(max_quant_steps > 0); + for (unsigned int i = 0; i < (max_quant_steps + 4); i++) + { + // Lane<0> = Best error + // Lane<1> = Best scale; -1 indicates no solution found + // Lane<2> = Cut low weight + best_results[i] = vfloat4(ERROR_CALC_DEFAULT, -1.0f, 0.0f, 0.0f); + } + + promise(max_angular_steps > 0); + for (unsigned int i = 0; i < max_angular_steps; i++) + { + float i_flt = static_cast<float>(i); + + int idx_span = weight_span[i]; + + float error_cut_low = error[i] + cut_low_weight_error[i]; + float error_cut_high = error[i] + cut_high_weight_error[i]; + float error_cut_low_high = error[i] + cut_low_weight_error[i] + cut_high_weight_error[i]; + + // Check best error against record N + vfloat4 best_result = best_results[idx_span]; + vfloat4 new_result = vfloat4(error[i], i_flt, 0.0f, 0.0f); + vmask4 mask = vfloat4(best_result.lane<0>()) > vfloat4(error[i]); + best_results[idx_span] = select(best_result, new_result, mask); + + // Check best error against record N-1 with either cut low or cut high + best_result = best_results[idx_span - 1]; + + new_result = vfloat4(error_cut_low, i_flt, 1.0f, 0.0f); + mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low); + best_result = select(best_result, new_result, mask); + + new_result = vfloat4(error_cut_high, i_flt, 0.0f, 0.0f); + mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_high); + best_results[idx_span - 1] = select(best_result, new_result, mask); + + // Check best error against record N-2 with both cut low and high + best_result = best_results[idx_span - 2]; + new_result = vfloat4(error_cut_low_high, i_flt, 1.0f, 0.0f); + mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low_high); + best_results[idx_span - 2] = select(best_result, new_result, mask); + } + + for (unsigned int i = 0; i <= max_quant_level; i++) + { + unsigned int q = steps_for_quant_level[i]; + int bsi = static_cast<int>(best_results[q].lane<1>()); + + // Did we find anything? +#if defined(ASTCENC_DIAGNOSTICS) + if ((bsi < 0) && print_once) + { + print_once = false; + printf("INFO: Unable to find full encoding within search error limit.\n\n"); + } +#endif + + bsi = astc::max(0, bsi); + + float lwi = lowest_weight[bsi] + best_results[q].lane<2>(); + float hwi = lwi + static_cast<float>(q) - 1.0f; + + float stepsize = 1.0f / (1.0f + static_cast<float>(bsi)); + low_value[i] = (angular_offsets[bsi] + lwi) * stepsize; + high_value[i] = (angular_offsets[bsi] + hwi) * stepsize; + } +} + +/* See header for documentation. */ +void compute_angular_endpoints_1plane( + bool only_always, + const block_size_descriptor& bsd, + const float* dec_weight_ideal_value, + unsigned int max_weight_quant, + compression_working_buffers& tmpbuf +) { + float (&low_value)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value1; + float (&high_value)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value1; + + float (&low_values)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values1; + float (&high_values)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values1; + + unsigned int max_decimation_modes = only_always ? bsd.decimation_mode_count_always + : bsd.decimation_mode_count_selected; + promise(max_decimation_modes > 0); + for (unsigned int i = 0; i < max_decimation_modes; i++) + { + const decimation_mode& dm = bsd.decimation_modes[i]; + if (!dm.is_ref_1_plane(static_cast<quant_method>(max_weight_quant))) + { + continue; + } + + unsigned int weight_count = bsd.get_decimation_info(i).weight_count; + + unsigned int max_precision = dm.maxprec_1plane; + if (max_precision > TUNE_MAX_ANGULAR_QUANT) + { + max_precision = TUNE_MAX_ANGULAR_QUANT; + } + + if (max_precision > max_weight_quant) + { + max_precision = max_weight_quant; + } + + compute_angular_endpoints_for_quant_levels( + weight_count, + dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS, + max_precision, low_values[i], high_values[i]); + } + + unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always + : bsd.block_mode_count_1plane_selected; + promise(max_block_modes > 0); + for (unsigned int i = 0; i < max_block_modes; i++) + { + const block_mode& bm = bsd.block_modes[i]; + assert(!bm.is_dual_plane); + + unsigned int quant_mode = bm.quant_mode; + unsigned int decim_mode = bm.decimation_mode; + + if (quant_mode <= TUNE_MAX_ANGULAR_QUANT) + { + low_value[i] = low_values[decim_mode][quant_mode]; + high_value[i] = high_values[decim_mode][quant_mode]; + } + else + { + low_value[i] = 0.0f; + high_value[i] = 1.0f; + } + } +} + +/* See header for documentation. */ +void compute_angular_endpoints_2planes( + const block_size_descriptor& bsd, + const float* dec_weight_ideal_value, + unsigned int max_weight_quant, + compression_working_buffers& tmpbuf +) { + float (&low_value1)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value1; + float (&high_value1)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value1; + float (&low_value2)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value2; + float (&high_value2)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value2; + + float (&low_values1)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values1; + float (&high_values1)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values1; + float (&low_values2)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values2; + float (&high_values2)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values2; + + promise(bsd.decimation_mode_count_selected > 0); + for (unsigned int i = 0; i < bsd.decimation_mode_count_selected; i++) + { + const decimation_mode& dm = bsd.decimation_modes[i]; + if (!dm.is_ref_2_plane(static_cast<quant_method>(max_weight_quant))) + { + continue; + } + + unsigned int weight_count = bsd.get_decimation_info(i).weight_count; + + unsigned int max_precision = dm.maxprec_2planes; + if (max_precision > TUNE_MAX_ANGULAR_QUANT) + { + max_precision = TUNE_MAX_ANGULAR_QUANT; + } + + if (max_precision > max_weight_quant) + { + max_precision = max_weight_quant; + } + + compute_angular_endpoints_for_quant_levels( + weight_count, + dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS, + max_precision, low_values1[i], high_values1[i]); + + compute_angular_endpoints_for_quant_levels( + weight_count, + dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET, + max_precision, low_values2[i], high_values2[i]); + } + + unsigned int start = bsd.block_mode_count_1plane_selected; + unsigned int end = bsd.block_mode_count_1plane_2plane_selected; + for (unsigned int i = start; i < end; i++) + { + const block_mode& bm = bsd.block_modes[i]; + unsigned int quant_mode = bm.quant_mode; + unsigned int decim_mode = bm.decimation_mode; + + if (quant_mode <= TUNE_MAX_ANGULAR_QUANT) + { + low_value1[i] = low_values1[decim_mode][quant_mode]; + high_value1[i] = high_values1[decim_mode][quant_mode]; + low_value2[i] = low_values2[decim_mode][quant_mode]; + high_value2[i] = high_values2[decim_mode][quant_mode]; + } + else + { + low_value1[i] = 0.0f; + high_value1[i] = 1.0f; + low_value2[i] = 0.0f; + high_value2[i] = 1.0f; + } + } +} + +#endif diff --git a/thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp b/thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp new file mode 100644 index 0000000000..8fdf73adc2 --- /dev/null +++ b/thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2011-2021 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief Data tables for quantization transfer. + */ + +#include "astcenc_internal.h" + +#define _ 0 // Using _ to indicate an entry that will not be used. + +const quant_and_transfer_table quant_and_xfer_tables[12] { + // QUANT2, range 0..1 + { + {0, 64}, + {0, 1}, + {0, 64}, + {0x4000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, + _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, + 0x4000} + }, + // QUANT_3, range 0..2 + { + {0, 32, 64}, + {0, 1, 2}, + {0, 32, 64}, + {0x2000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, + _,_,0x4000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, + _,_,_,_,0x4020} + }, + // QUANT_4, range 0..3 + { + {0, 21, 43, 64}, + {0, 1, 2, 3}, + {0, 21, 43, 64}, + {0x1500,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x2b00,_,_,_,_, + _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x4015,_,_,_,_,_,_,_,_,_,_,_,_, + _,_,_,_,_,_,_,_,0x402b} + }, + //QUANT_5, range 0..4 + { + {0, 16, 32, 48, 64}, + {0, 1, 2, 3, 4}, + {0, 16, 32, 48, 64}, + {0x1000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x2000,_,_,_,_,_,_,_,_,_, + _,_,_,_,_,_,0x3010,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x4020,_,_,_, + _,_,_,_,_,_,_,_,_,_,_,_,0x4030} + }, + // QUANT_6, range 0..5 + { + {0, 12, 25, 39, 52, 64}, + {0, 2, 4, 5, 3, 1}, + {0, 64, 12, 52, 25, 39}, + {0x0c00,_,_,_,_,_,_,_,_,_,_,_,0x1900,_,_,_,_,_,_,_,_,_,_,_,_, + 0x270c,_,_,_,_,_,_,_,_,_,_,_,_,_,0x3419,_,_,_,_,_,_,_,_,_,_, + _,_,0x4027,_,_,_,_,_,_,_,_,_,_,_,0x4034} + }, + // QUANT_8, range 0..7 + { + {0, 9, 18, 27, 37, 46, 55, 64}, + {0, 1, 2, 3, 4, 5, 6, 7}, + {0, 9, 18, 27, 37, 46, 55, 64}, + {0x0900,_,_,_,_,_,_,_,_,0x1200,_,_,_,_,_,_,_,_,0x1b09,_,_, + _,_,_,_,_,_,0x2512,_,_,_,_,_,_,_,_,_,0x2e1b,_,_,_,_,_,_,_,_, + 0x3725,_,_,_,_,_,_,_,_,0x402e,_,_,_,_,_,_,_,_,0x4037} + }, + // QUANT_10, range 0..9 + { + {0, 7, 14, 21, 28, 36, 43, 50, 57, 64}, + {0, 2, 4, 6, 8, 9, 7, 5, 3, 1}, + {0, 64, 7, 57, 14, 50, 21, 43, 28, 36}, + {0x0700,_,_,_,_,_,_,0x0e00,_,_,_,_,_,_,0x1507,_,_,_,_,_,_, + 0x1c0e,_,_,_,_,_,_,0x2415,_,_,_,_,_,_,_,0x2b1c,_,_,_,_,_, + _,0x3224,_,_,_,_,_,_,0x392b,_,_,_,_,_,_,0x4032,_,_,_,_,_, + _,0x4039} + }, + // QUANT_12, range 0..11 + { + {0, 5, 11, 17, 23, 28, 36, 41, 47, 53, 59, 64}, + {0, 4, 8, 2, 6, 10, 11, 7, 3, 9, 5, 1}, + {0, 64, 17, 47, 5, 59, 23, 41, 11, 53, 28, 36}, + {0x0500,_,_,_,_,0x0b00,_,_,_,_,_,0x1105,_,_,_,_,_, + 0x170b,_,_,_,_,_,0x1c11,_,_,_,_,0x2417,_,_,_,_,_,_,_, + 0x291c,_,_,_,_,0x2f24,_,_,_,_,_,0x3529,_,_,_,_,_, + 0x3b2f,_,_,_,_,_,0x4035,_,_,_,_,0x403b} + }, + // QUANT_16, range 0..15 + { + {0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64}, + {0x0400,_,_,_,0x0800,_,_,_,0x0c04,_,_,_,0x1108,_,_,_,_, + 0x150c,_,_,_,0x1911,_,_,_,0x1d15,_,_,_,0x2319,_,_,_,_, + _,0x271d,_,_,_,0x2b23,_,_,_,0x2f27,_,_,_,0x342b,_,_,_, + _,0x382f,_,_,_,0x3c34,_,_,_,0x4038,_,_,_,0x403c} + }, + // QUANT_20, range 0..19 + { + {0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 35, 38, 41, 45, 48, 51, 55, 58, 61, 64}, + {0, 4, 8, 12, 16, 2, 6, 10, 14, 18, 19, 15, 11, 7, 3, 17, 13, 9, 5, 1}, + {0, 64, 16, 48, 3, 61, 19, 45, 6, 58, 23, 41, 9, 55, 26, 38, 13, 51, 29, 35}, + {0x0300,_,_,0x0600,_,_,0x0903,_,_,0x0d06,_,_,_, + 0x1009,_,_,0x130d,_,_,0x1710,_,_,_,0x1a13,_,_, + 0x1d17,_,_,0x231a,_,_,_,_,_,0x261d,_,_,0x2923,_,_, + 0x2d26,_,_,_,0x3029,_,_,0x332d,_,_,0x3730,_,_,_, + 0x3a33,_,_,0x3d37,_,_,0x403a,_,_,0x403d} + }, + // QUANT_24, range 0..23 + { + {0, 2, 5, 8, 11, 13, 16, 19, 22, 24, 27, 30, 34, 37, 40, 42, 45, 48, 51, 53, 56, 59, 62, 64}, + {0, 8, 16, 2, 10, 18, 4, 12, 20, 6, 14, 22, 23, 15, 7, 21, 13, 5, 19, 11, 3, 17, 9, 1}, + {0, 64, 8, 56, 16, 48, 24, 40, 2, 62, 11, 53, 19, 45, 27, 37, 5, 59, 13, 51, 22, 42, 30, 34}, + {0x0200,_,0x0500,_,_,0x0802,_,_,0x0b05,_,_,0x0d08, + _,0x100b,_,_,0x130d,_,_,0x1610,_,_,0x1813,_, + 0x1b16,_,_,0x1e18,_,_,0x221b,_,_,_,0x251e,_,_, + 0x2822,_,_,0x2a25,_,0x2d28,_,_,0x302a,_,_,0x332d, + _,_,0x3530,_,0x3833,_,_,0x3b35,_,_,0x3e38,_,_, + 0x403b,_,0x403e} + }, + // QUANT_32, range 0..31 + { + {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64}, + {0x0200,_,0x0400,_,0x0602,_,0x0804,_,0x0a06,_, + 0x0c08,_,0x0e0a,_,0x100c,_,0x120e,_,0x1410,_, + 0x1612,_,0x1814,_,0x1a16,_,0x1c18,_,0x1e1a,_, + 0x221c,_,_,_,0x241e,_,0x2622,_,0x2824,_,0x2a26,_, + 0x2c28,_,0x2e2a,_,0x302c,_,0x322e,_,0x3430,_, + 0x3632,_,0x3834,_,0x3a36,_,0x3c38,_,0x3e3a,_, + 0x403c,_,0x403e} + } +}; diff --git a/thirdparty/astcenc/patches/fix-build-no-ssse3.patch b/thirdparty/astcenc/patches/fix-build-no-ssse3.patch new file mode 100644 index 0000000000..9da4f3e1f3 --- /dev/null +++ b/thirdparty/astcenc/patches/fix-build-no-ssse3.patch @@ -0,0 +1,81 @@ +From 02c22d3df501dc284ba732fa82a6c408c57b3237 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= <rverschelde@gmail.com> +Date: Thu, 19 Jan 2023 23:30:13 +0100 +Subject: [PATCH] mathlib: Remove incomplete support for SSE3 which assumed + SSSE3 + +`_mm_shuffle_epi8` requires SSSE3 so the check on `ASTCENC_SSE >= 30` is +too lax and would fail if `__SSE3__` is supported, but not `__SSSE3__`. + +The only supported configurations are SSE2, SSE4.1, and AVX2, so as +discussed in #393 we drop the SSE3 checks and require SSE4.1 instead. +--- + Source/astcenc_mathlib.h | 2 -- + Source/astcenc_vecmathlib_sse_4.h | 10 +++++----- + 2 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/Source/astcenc_mathlib.h b/Source/astcenc_mathlib.h +index 67e989e..0540c4f 100644 +--- a/Source/astcenc_mathlib.h ++++ b/Source/astcenc_mathlib.h +@@ -48,8 +48,6 @@ + #define ASTCENC_SSE 42 + #elif defined(__SSE4_1__) + #define ASTCENC_SSE 41 +- #elif defined(__SSE3__) +- #define ASTCENC_SSE 30 + #elif defined(__SSE2__) + #define ASTCENC_SSE 20 + #else +diff --git a/Source/astcenc_vecmathlib_sse_4.h b/Source/astcenc_vecmathlib_sse_4.h +index 76fe577..26dcc4a 100644 +--- a/Source/astcenc_vecmathlib_sse_4.h ++++ b/Source/astcenc_vecmathlib_sse_4.h +@@ -1046,7 +1046,7 @@ ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p) + */ + ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p) + { +-#if ASTCENC_SSE >= 30 ++#if ASTCENC_SSE >= 41 + t0p = t0; + t1p = t0 ^ t1; + #else +@@ -1062,7 +1062,7 @@ ASTCENC_SIMD_INLINE void vtable_prepare( + vint4 t0, vint4 t1, vint4 t2, vint4 t3, + vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p) + { +-#if ASTCENC_SSE >= 30 ++#if ASTCENC_SSE >= 41 + t0p = t0; + t1p = t0 ^ t1; + t2p = t1 ^ t2; +@@ -1080,7 +1080,7 @@ ASTCENC_SIMD_INLINE void vtable_prepare( + */ + ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx) + { +-#if ASTCENC_SSE >= 30 ++#if ASTCENC_SSE >= 41 + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00))); + +@@ -1102,7 +1102,7 @@ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx) + */ + ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx) + { +-#if ASTCENC_SSE >= 30 ++#if ASTCENC_SSE >= 41 + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00))); + +@@ -1130,7 +1130,7 @@ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx) + */ + ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx) + { +-#if ASTCENC_SSE >= 30 ++#if ASTCENC_SSE >= 41 + // Set index byte MSB to 1 for unused bytes so shuffle returns zero + __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00))); + +-- +2.39.1 + |