diff options
563 files changed, 13138 insertions, 10410 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e7e88e95d7..bd4eb906c0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -114,7 +114,6 @@ doc_classes/* @godotengine/documentation /modules/gdscript/ @godotengine/gdscript /modules/jsonrpc/ @godotengine/gdscript /modules/mono/ @godotengine/mono -/modules/visual_script/ @godotengine/visualscript ## Text /modules/freetype/ @godotengine/buildsystem diff --git a/SConstruct b/SConstruct index f7504f72e1..200e8e5984 100644 --- a/SConstruct +++ b/SConstruct @@ -170,7 +170,7 @@ opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectur opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64"))) opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none"))) opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False)) -opts.Add(EnumVariable("lto", "Link-time optimization (for production buids)", "none", ("none", "thin", "full"))) +opts.Add(EnumVariable("lto", "Link-time optimization (for production buids)", "none", ("none", "auto", "thin", "full"))) # Components opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True)) @@ -460,36 +460,17 @@ if selected_platform in platform_list: env["LINKFLAGS"] = "" env.Append(LINKFLAGS=str(LINKFLAGS).split()) - # Platform specific flags + # Platform specific flags. + # These can sometimes override default options. flag_list = platform_flags[selected_platform] for f in flag_list: if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags env[f[0]] = f[1] - # Must happen after the flags' definition, so that they can be used by platform detect - detect.configure(env) - - print( - 'Building for platform "%s", architecture "%s", %s, target "%s".' - % (selected_platform, env["arch"], "editor" if env["tools"] else "template", env["target"]) - ) - - # Set our C and C++ standard requirements. - # C++17 is required as we need guaranteed copy elision as per GH-36436. - # Prepending to make it possible to override. - # This needs to come after `configure`, otherwise we don't have env.msvc. - if not env.msvc: - # Specifying GNU extensions support explicitly, which are supported by - # both GCC and Clang. Both currently default to gnu11 and gnu++14. - env.Prepend(CFLAGS=["-std=gnu11"]) - env.Prepend(CXXFLAGS=["-std=gnu++17"]) - else: - # MSVC doesn't have clear C standard support, /std only covers C++. - # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features. - env.Prepend(CCFLAGS=["/std:c++17"]) - - # 'dev' and 'production' are aliases to set default options if they haven't been set - # manually by the user. + # 'dev' and 'production' are aliases to set default options if they haven't been + # set manually by the user. + # These need to be checked *after* platform specific flags so that different + # default values can be set (e.g. to keep LTO off for `production` on some platforms). if env["dev"]: env["verbose"] = methods.get_cmdline_bool("verbose", True) env["warnings"] = ARGUMENTS.get("warnings", "extra") @@ -498,27 +479,43 @@ if selected_platform in platform_list: env["tests"] = methods.get_cmdline_bool("tests", True) if env["production"]: env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True) - env["lto"] = ARGUMENTS.get("lto", "full") env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False) + # LTO "auto" means we handle the preferred option in each platform detect.py. + env["lto"] = ARGUMENTS.get("lto", "auto") if not env["tools"] and env["target"] == "debug": print( "WARNING: Requested `production` build with `tools=no target=debug`, " "this will give you a full debug template (use `target=release_debug` " "for an optimized template with debug features)." ) - if env.msvc: - print( - "WARNING: For `production` Windows builds, you should use MinGW with GCC " - "or Clang instead of Visual Studio, as they can better optimize the " - "GDScript VM in a very significant way. MSVC LTO also doesn't work " - "reliably for our use case." - "If you want to use MSVC nevertheless for production builds, set " - "`debug_symbols=no lto=none` instead of the `production=yes` option." - ) - Exit(255) + + # Must happen after the flags' definition, as configure is when most flags + # are actually handled to change compile options, etc. + detect.configure(env) + + # Needs to happen after configure to handle "auto". if env["lto"] != "none": print("Using LTO: " + env["lto"]) + # Set our C and C++ standard requirements. + # C++17 is required as we need guaranteed copy elision as per GH-36436. + # Prepending to make it possible to override. + # This needs to come after `configure`, otherwise we don't have env.msvc. + if not env.msvc: + # Specifying GNU extensions support explicitly, which are supported by + # both GCC and Clang. Both currently default to gnu11 and gnu++14. + env.Prepend(CFLAGS=["-std=gnu11"]) + env.Prepend(CXXFLAGS=["-std=gnu++17"]) + else: + # MSVC doesn't have clear C standard support, /std only covers C++. + # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features. + env.Prepend(CCFLAGS=["/std:c++17"]) + + print( + 'Building for platform "%s", architecture "%s", %s, target "%s".' + % (selected_platform, env["arch"], "editor" if env["tools"] else "template", env["target"]) + ) + # Enforce our minimal compiler version requirements cc_version = methods.get_compiler_version(env) or { "major": None, @@ -737,7 +734,7 @@ if selected_platform in platform_list: env.module_list = modules_enabled methods.sort_module_list(env) - methods.update_version(env.module_version_string) + methods.generate_version_header(env.module_version_string) env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"] env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 6275502378..15f807017f 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -101,10 +101,15 @@ const PackedStringArray ProjectSettings::_get_supported_features() { features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH)); features.append(VERSION_FULL_CONFIG); features.append(VERSION_FULL_BUILD); - // For now, assume Vulkan is always supported. - // This should be removed if it's possible to build the editor without Vulkan. - features.append("Vulkan Clustered"); - features.append("Vulkan Mobile"); + +#ifdef VULKAN_ENABLED + features.append("Forward Plus"); + features.append("Mobile"); +#endif + +#ifdef GLES3_ENABLED + features.append("GL Compatibility"); +#endif return features; } @@ -909,7 +914,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust project_features = ProjectSettings::get_required_features(); } // Check the rendering API. - const String rendering_api = has_setting("rendering/quality/driver/driver_name") ? (String)get_setting("rendering/quality/driver/driver_name") : String(); + const String rendering_api = has_setting("rendering/renderer/rendering_method") ? (String)get_setting("rendering/renderer/rendering_method") : String(); if (!rendering_api.is_empty()) { // Add the rendering API as a project feature if it doesn't already exist. if (!project_features.has(rendering_api)) { @@ -1139,6 +1144,7 @@ void ProjectSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order); ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value); ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &ProjectSettings::_add_property_info_bind); + ClassDB::bind_method(D_METHOD("set_restart_if_changed", "name", "restart"), &ProjectSettings::set_restart_if_changed); ClassDB::bind_method(D_METHOD("clear", "name"), &ProjectSettings::clear); ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path); ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index a9af63ee39..960dfe0395 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -45,9 +45,10 @@ public: static const String PROJECT_DATA_DIR_NAME_SUFFIX; enum { - //properties that are not for built in values begin from this value, so builtin ones are displayed first + // Properties that are not for built in values begin from this value, so builtin ones are displayed first. NO_BUILTIN_ORDER_BASE = 1 << 16 }; + #ifdef TOOLS_ENABLED const static PackedStringArray get_required_features(); const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 9daf58cb71..2149ee4512 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -322,6 +322,14 @@ String OS::get_name() const { return ::OS::get_singleton()->get_name(); } +String OS::get_distribution_name() const { + return ::OS::get_singleton()->get_distribution_name(); +} + +String OS::get_version() const { + return ::OS::get_singleton()->get_version(); +} + Vector<String> OS::get_cmdline_args() { List<String> cmdline = ::OS::get_singleton()->get_cmdline_args(); Vector<String> cmdlinev; @@ -535,6 +543,8 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment); ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name); + ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name); + ClassDB::bind_method(D_METHOD("get_version"), &OS::get_version); ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args); ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args); @@ -800,14 +810,13 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) { ::Geometry2D::make_atlas(rects, result, size); - Size2 r_size = size; Vector<Point2> r_result; for (int i = 0; i < result.size(); i++) { r_result.push_back(result[i]); } ret["points"] = r_result; - ret["size"] = r_size; + ret["size"] = size; return ret; } @@ -982,636 +991,6 @@ void Geometry3D::_bind_methods() { ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon); } -////// File ////// - -Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) { - Error err = open(p_path, p_mode_flags); - if (err) { - return err; - } - - Ref<FileAccessEncrypted> fae; - fae.instantiate(); - err = fae->open_and_parse(f, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); - if (err) { - close(); - return err; - } - f = fae; - return OK; -} - -Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) { - Error err = open(p_path, p_mode_flags); - if (err) { - return err; - } - - Ref<FileAccessEncrypted> fae; - fae.instantiate(); - err = fae->open_and_parse_password(f, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); - if (err) { - close(); - return err; - } - - f = fae; - return OK; -} - -Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) { - Ref<FileAccessCompressed> fac; - fac.instantiate(); - fac->configure("GCPF", (Compression::Mode)p_compress_mode); - - Error err = fac->_open(p_path, p_mode_flags); - - if (err) { - return err; - } - - f = fac; - return OK; -} - -Error File::open(const String &p_path, ModeFlags p_mode_flags) { - Error err; - f = FileAccess::open(p_path, p_mode_flags, &err); - if (f.is_valid()) { - f->set_big_endian(big_endian); - } - return err; -} - -void File::flush() { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing."); - f->flush(); -} - -void File::close() { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened."); - f.unref(); -} - -bool File::is_open() const { - return f != nullptr; -} - -String File::get_path() const { - ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission."); - return f->get_path(); -} - -String File::get_path_absolute() const { - ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission."); - return f->get_path_absolute(); -} - -void File::seek(int64_t p_position) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer."); - f->seek(p_position); -} - -void File::seek_end(int64_t p_position) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - f->seek_end(p_position); -} - -uint64_t File::get_position() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_position(); -} - -uint64_t File::get_length() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_length(); -} - -bool File::eof_reached() const { - ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use, or is lacking read-write permission."); - return f->eof_reached(); -} - -uint8_t File::get_8() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_8(); -} - -uint16_t File::get_16() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_16(); -} - -uint32_t File::get_32() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_32(); -} - -uint64_t File::get_64() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_64(); -} - -float File::get_float() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_float(); -} - -double File::get_double() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_double(); -} - -real_t File::get_real() const { - ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); - return f->get_real(); -} - -Vector<uint8_t> File::get_buffer(int64_t p_length) const { - Vector<uint8_t> data; - ERR_FAIL_COND_V_MSG(f.is_null(), data, "File must be opened before use, or is lacking read-write permission."); - - ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0."); - if (p_length == 0) { - return data; - } - - Error err = data.resize(p_length); - ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements."); - - uint8_t *w = data.ptrw(); - int64_t len = f->get_buffer(&w[0], p_length); - - if (len < p_length) { - data.resize(len); - } - - return data; -} - -String File::get_as_text(bool p_skip_cr) const { - ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission."); - - uint64_t original_pos = f->get_position(); - const_cast<FileAccess *>(*f)->seek(0); - - String text = f->get_as_utf8_string(p_skip_cr); - - const_cast<FileAccess *>(*f)->seek(original_pos); - - return text; -} - -String File::get_md5(const String &p_path) const { - return FileAccess::get_md5(p_path); -} - -String File::get_sha256(const String &p_path) const { - return FileAccess::get_sha256(p_path); -} - -String File::get_line() const { - ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission."); - return f->get_line(); -} - -Vector<String> File::get_csv_line(const String &p_delim) const { - ERR_FAIL_COND_V_MSG(f.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission."); - return f->get_csv_line(p_delim); -} - -/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac) - * It's not about the current CPU type but file formats. - * These flags get reset to false (little endian) on each open - */ - -void File::set_big_endian(bool p_big_endian) { - big_endian = p_big_endian; - if (f.is_valid()) { - f->set_big_endian(p_big_endian); - } -} - -bool File::is_big_endian() { - return big_endian; -} - -Error File::get_error() const { - if (f.is_null()) { - return ERR_UNCONFIGURED; - } - return f->get_error(); -} - -void File::store_8(uint8_t p_dest) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_8(p_dest); -} - -void File::store_16(uint16_t p_dest) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_16(p_dest); -} - -void File::store_32(uint32_t p_dest) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_32(p_dest); -} - -void File::store_64(uint64_t p_dest) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_64(p_dest); -} - -void File::store_float(float p_dest) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_float(p_dest); -} - -void File::store_double(double p_dest) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_double(p_dest); -} - -void File::store_real(real_t p_real) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_real(p_real); -} - -void File::store_string(const String &p_string) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_string(p_string); -} - -void File::store_pascal_string(const String &p_string) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - f->store_pascal_string(p_string); -} - -String File::get_pascal_string() { - ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission."); - - return f->get_pascal_string(); -} - -void File::store_line(const String &p_string) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - f->store_line(p_string); -} - -void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - f->store_csv_line(p_values, p_delim); -} - -void File::store_buffer(const Vector<uint8_t> &p_buffer) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - - uint64_t len = p_buffer.size(); - if (len == 0) { - return; - } - - const uint8_t *r = p_buffer.ptr(); - - f->store_buffer(&r[0], len); -} - -bool File::file_exists(const String &p_name) { - return FileAccess::exists(p_name); -} - -void File::store_var(const Variant &p_var, bool p_full_objects) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); - int len; - Error err = encode_variant(p_var, nullptr, len, p_full_objects); - ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); - - Vector<uint8_t> buff; - buff.resize(len); - - uint8_t *w = buff.ptrw(); - err = encode_variant(p_var, &w[0], len, p_full_objects); - ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); - - store_32(len); - store_buffer(buff); -} - -Variant File::get_var(bool p_allow_objects) const { - ERR_FAIL_COND_V_MSG(f.is_null(), Variant(), "File must be opened before use, or is lacking read-write permission."); - uint32_t len = get_32(); - Vector<uint8_t> buff = get_buffer(len); - ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant()); - - const uint8_t *r = buff.ptr(); - - Variant v; - Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects); - ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant."); - - return v; -} - -uint64_t File::get_modified_time(const String &p_file) const { - return FileAccess::get_modified_time(p_file); -} - -void File::_bind_methods() { - ClassDB::bind_method(D_METHOD("open_encrypted", "path", "mode_flags", "key"), &File::open_encrypted); - ClassDB::bind_method(D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &File::open_encrypted_pass); - ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &File::open_compressed, DEFVAL(0)); - - ClassDB::bind_method(D_METHOD("open", "path", "flags"), &File::open); - ClassDB::bind_method(D_METHOD("flush"), &File::flush); - ClassDB::bind_method(D_METHOD("close"), &File::close); - ClassDB::bind_method(D_METHOD("get_path"), &File::get_path); - ClassDB::bind_method(D_METHOD("get_path_absolute"), &File::get_path_absolute); - ClassDB::bind_method(D_METHOD("is_open"), &File::is_open); - ClassDB::bind_method(D_METHOD("seek", "position"), &File::seek); - ClassDB::bind_method(D_METHOD("seek_end", "position"), &File::seek_end, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_position"), &File::get_position); - ClassDB::bind_method(D_METHOD("get_length"), &File::get_length); - ClassDB::bind_method(D_METHOD("eof_reached"), &File::eof_reached); - ClassDB::bind_method(D_METHOD("get_8"), &File::get_8); - ClassDB::bind_method(D_METHOD("get_16"), &File::get_16); - ClassDB::bind_method(D_METHOD("get_32"), &File::get_32); - ClassDB::bind_method(D_METHOD("get_64"), &File::get_64); - ClassDB::bind_method(D_METHOD("get_float"), &File::get_float); - ClassDB::bind_method(D_METHOD("get_double"), &File::get_double); - ClassDB::bind_method(D_METHOD("get_real"), &File::get_real); - ClassDB::bind_method(D_METHOD("get_buffer", "length"), &File::get_buffer); - ClassDB::bind_method(D_METHOD("get_line"), &File::get_line); - ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &File::get_csv_line, DEFVAL(",")); - ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &File::get_as_text, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_md5", "path"), &File::get_md5); - ClassDB::bind_method(D_METHOD("get_sha256", "path"), &File::get_sha256); - ClassDB::bind_method(D_METHOD("is_big_endian"), &File::is_big_endian); - ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &File::set_big_endian); - ClassDB::bind_method(D_METHOD("get_error"), &File::get_error); - ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &File::get_var, DEFVAL(false)); - - ClassDB::bind_method(D_METHOD("store_8", "value"), &File::store_8); - ClassDB::bind_method(D_METHOD("store_16", "value"), &File::store_16); - ClassDB::bind_method(D_METHOD("store_32", "value"), &File::store_32); - ClassDB::bind_method(D_METHOD("store_64", "value"), &File::store_64); - ClassDB::bind_method(D_METHOD("store_float", "value"), &File::store_float); - ClassDB::bind_method(D_METHOD("store_double", "value"), &File::store_double); - ClassDB::bind_method(D_METHOD("store_real", "value"), &File::store_real); - ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &File::store_buffer); - ClassDB::bind_method(D_METHOD("store_line", "line"), &File::store_line); - ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &File::store_csv_line, DEFVAL(",")); - ClassDB::bind_method(D_METHOD("store_string", "string"), &File::store_string); - ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &File::store_var, DEFVAL(false)); - - ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string); - ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string); - - ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists); - ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian"); - - BIND_ENUM_CONSTANT(READ); - BIND_ENUM_CONSTANT(WRITE); - BIND_ENUM_CONSTANT(READ_WRITE); - BIND_ENUM_CONSTANT(WRITE_READ); - - BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ); - BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE); - BIND_ENUM_CONSTANT(COMPRESSION_ZSTD); - BIND_ENUM_CONSTANT(COMPRESSION_GZIP); -} - -////// Directory ////// - -Error Directory::open(const String &p_path) { - Error err; - Ref<DirAccess> alt = DirAccess::open(p_path, &err); - if (alt.is_null()) { - return err; - } - d = alt; - dir_open = true; - - return OK; -} - -bool Directory::is_open() const { - return d.is_valid() && dir_open; -} - -Error Directory::list_dir_begin() { - ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); - return d->list_dir_begin(); -} - -String Directory::get_next() { - ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); - - String next = d->get_next(); - while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && d->current_is_hidden()))) { - next = d->get_next(); - } - return next; -} - -bool Directory::current_is_dir() const { - ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use."); - return d->current_is_dir(); -} - -void Directory::list_dir_end() { - ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use."); - d->list_dir_end(); -} - -PackedStringArray Directory::get_files() { - return _get_contents(false); -} - -PackedStringArray Directory::get_directories() { - return _get_contents(true); -} - -PackedStringArray Directory::_get_contents(bool p_directories) { - PackedStringArray ret; - ERR_FAIL_COND_V_MSG(!is_open(), ret, "Directory must be opened before use."); - - list_dir_begin(); - String s = get_next(); - while (!s.is_empty()) { - if (current_is_dir() == p_directories) { - ret.append(s); - } - s = get_next(); - } - - ret.sort(); - return ret; -} - -void Directory::set_include_navigational(bool p_enable) { - include_navigational = p_enable; -} - -bool Directory::get_include_navigational() const { - return include_navigational; -} - -void Directory::set_include_hidden(bool p_enable) { - include_hidden = p_enable; -} - -bool Directory::get_include_hidden() const { - return include_hidden; -} - -int Directory::get_drive_count() { - ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); - return d->get_drive_count(); -} - -String Directory::get_drive(int p_drive) { - ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); - return d->get_drive(p_drive); -} - -int Directory::get_current_drive() { - ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); - return d->get_current_drive(); -} - -Error Directory::change_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly."); - Error err = d->change_dir(p_dir); - - if (err != OK) { - return err; - } - dir_open = true; - - return OK; -} - -String Directory::get_current_dir() { - ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); - return d->get_current_dir(); -} - -Error Directory::make_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly."); - if (!p_dir.is_relative_path()) { - Ref<DirAccess> da = DirAccess::create_for_path(p_dir); - return da->make_dir(p_dir); - } - return d->make_dir(p_dir); -} - -Error Directory::make_dir_recursive(String p_dir) { - ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly."); - if (!p_dir.is_relative_path()) { - Ref<DirAccess> da = DirAccess::create_for_path(p_dir); - return da->make_dir_recursive(p_dir); - } - return d->make_dir_recursive(p_dir); -} - -bool Directory::file_exists(String p_file) { - ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly."); - if (!p_file.is_relative_path()) { - return FileAccess::exists(p_file); - } - return d->file_exists(p_file); -} - -bool Directory::dir_exists(String p_dir) { - ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly."); - if (!p_dir.is_relative_path()) { - return DirAccess::exists(p_dir); - } - return d->dir_exists(p_dir); -} - -uint64_t Directory::get_space_left() { - ERR_FAIL_COND_V_MSG(d.is_null(), 0, "Directory must be opened before use."); - return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB. -} - -Error Directory::copy(String p_from, String p_to) { - ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); - return d->copy(p_from, p_to); -} - -Error Directory::rename(String p_from, String p_to) { - ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); - ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename."); - - if (!p_from.is_relative_path()) { - Ref<DirAccess> da = DirAccess::create_for_path(p_from); - ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist."); - return da->rename(p_from, p_to); - } - - ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist."); - return d->rename(p_from, p_to); -} - -Error Directory::remove(String p_name) { - ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); - if (!p_name.is_relative_path()) { - Ref<DirAccess> da = DirAccess::create_for_path(p_name); - return da->remove(p_name); - } - - return d->remove(p_name); -} - -void Directory::_bind_methods() { - ClassDB::bind_method(D_METHOD("open", "path"), &Directory::open); - ClassDB::bind_method(D_METHOD("list_dir_begin"), &Directory::list_dir_begin, DEFVAL(false), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_next"), &Directory::get_next); - ClassDB::bind_method(D_METHOD("current_is_dir"), &Directory::current_is_dir); - ClassDB::bind_method(D_METHOD("list_dir_end"), &Directory::list_dir_end); - ClassDB::bind_method(D_METHOD("get_files"), &Directory::get_files); - ClassDB::bind_method(D_METHOD("get_directories"), &Directory::get_directories); - ClassDB::bind_method(D_METHOD("get_drive_count"), &Directory::get_drive_count); - ClassDB::bind_method(D_METHOD("get_drive", "idx"), &Directory::get_drive); - ClassDB::bind_method(D_METHOD("get_current_drive"), &Directory::get_current_drive); - ClassDB::bind_method(D_METHOD("change_dir", "todir"), &Directory::change_dir); - ClassDB::bind_method(D_METHOD("get_current_dir"), &Directory::get_current_dir); - ClassDB::bind_method(D_METHOD("make_dir", "path"), &Directory::make_dir); - ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive); - ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists); - ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists); - ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left); - ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy); - ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename); - ClassDB::bind_method(D_METHOD("remove", "path"), &Directory::remove); - - ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &Directory::set_include_navigational); - ClassDB::bind_method(D_METHOD("get_include_navigational"), &Directory::get_include_navigational); - ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &Directory::set_include_hidden); - ClassDB::bind_method(D_METHOD("get_include_hidden"), &Directory::get_include_hidden); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden"); -} - -Directory::Directory() { - d = DirAccess::create(DirAccess::ACCESS_RESOURCES); -} - ////// Marshalls ////// Marshalls *Marshalls::singleton = nullptr; diff --git a/core/core_bind.h b/core/core_bind.h index cd382d2915..345c517b99 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -193,6 +193,8 @@ public: bool set_environment(const String &p_var, const String &p_value) const; String get_name() const; + String get_distribution_name() const; + String get_version() const; Vector<String> get_cmdline_args(); Vector<String> get_cmdline_user_args(); @@ -353,156 +355,6 @@ public: Geometry3D() { singleton = this; } }; -class File : public RefCounted { - GDCLASS(File, RefCounted); - - Ref<FileAccess> f; - bool big_endian = false; - -protected: - static void _bind_methods(); - -public: - enum ModeFlags { - READ = 1, - WRITE = 2, - READ_WRITE = 3, - WRITE_READ = 7, - }; - - enum CompressionMode { - COMPRESSION_FASTLZ = Compression::MODE_FASTLZ, - COMPRESSION_DEFLATE = Compression::MODE_DEFLATE, - COMPRESSION_ZSTD = Compression::MODE_ZSTD, - COMPRESSION_GZIP = Compression::MODE_GZIP - }; - - Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key); - Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass); - Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ); - - Error open(const String &p_path, ModeFlags p_mode_flags); // open a file. - void flush(); // Flush a file (write its buffer to disk). - void close(); // Close a file. - bool is_open() const; // True when file is open. - - String get_path() const; // Returns the path for the current open file. - String get_path_absolute() const; // Returns the absolute path for the current open file. - - void seek(int64_t p_position); // Seek to a given position. - void seek_end(int64_t p_position = 0); // Seek from the end of file. - uint64_t get_position() const; // Get position in the file. - uint64_t get_length() const; // Get size of the file. - - bool eof_reached() const; // Reading passed EOF. - - uint8_t get_8() const; // Get a byte. - uint16_t get_16() const; // Get 16 bits uint. - uint32_t get_32() const; // Get 32 bits uint. - uint64_t get_64() const; // Get 64 bits uint. - - float get_float() const; - double get_double() const; - real_t get_real() const; - - Variant get_var(bool p_allow_objects = false) const; - - Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes. - String get_line() const; - Vector<String> get_csv_line(const String &p_delim = ",") const; - String get_as_text(bool p_skip_cr = false) const; - String get_md5(const String &p_path) const; - String get_sha256(const String &p_path) const; - - /* - * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac). - * It's not about the current CPU type but file formats. - * This flag gets reset to `false` (little endian) on each open. - */ - void set_big_endian(bool p_big_endian); - bool is_big_endian(); - - Error get_error() const; // Get last error. - - void store_8(uint8_t p_dest); // Store a byte. - void store_16(uint16_t p_dest); // Store 16 bits uint. - void store_32(uint32_t p_dest); // Store 32 bits uint. - void store_64(uint64_t p_dest); // Store 64 bits uint. - - void store_float(float p_dest); - void store_double(double p_dest); - void store_real(real_t p_real); - - void store_string(const String &p_string); - void store_line(const String &p_string); - void store_csv_line(const Vector<String> &p_values, const String &p_delim = ","); - - virtual void store_pascal_string(const String &p_string); - virtual String get_pascal_string(); - - void store_buffer(const Vector<uint8_t> &p_buffer); // Store an array of bytes. - - void store_var(const Variant &p_var, bool p_full_objects = false); - - static bool file_exists(const String &p_name); // Return true if a file exists. - - uint64_t get_modified_time(const String &p_file) const; - - File() {} -}; - -class Directory : public RefCounted { - GDCLASS(Directory, RefCounted); - Ref<DirAccess> d; - - bool dir_open = false; - bool include_navigational = false; - bool include_hidden = false; - -protected: - static void _bind_methods(); - -public: - Error open(const String &p_path); - - bool is_open() const; - - Error list_dir_begin(); - String get_next(); - bool current_is_dir() const; - void list_dir_end(); - - PackedStringArray get_files(); - PackedStringArray get_directories(); - PackedStringArray _get_contents(bool p_directories); - - void set_include_navigational(bool p_enable); - bool get_include_navigational() const; - void set_include_hidden(bool p_enable); - bool get_include_hidden() const; - - int get_drive_count(); - String get_drive(int p_drive); - int get_current_drive(); - - Error change_dir(String p_dir); // Can be relative or absolute, return false on success. - String get_current_dir(); // Return current dir location. - - Error make_dir(String p_dir); - Error make_dir_recursive(String p_dir); - - bool file_exists(String p_file); - bool dir_exists(String p_dir); - - uint64_t get_space_left(); - - Error copy(String p_from, String p_to); - Error rename(String p_from, String p_to); - Error remove(String p_name); - - Directory(); -}; - class Marshalls : public Object { GDCLASS(Marshalls, Object); @@ -736,9 +588,6 @@ VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType); -VARIANT_ENUM_CAST(core_bind::File::ModeFlags); -VARIANT_ENUM_CAST(core_bind::File::CompressionMode); - VARIANT_ENUM_CAST(core_bind::Thread::Priority); #endif // CORE_BIND_H diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp index ef0b590030..67dc55bdb7 100644 --- a/core/extension/gdnative_interface.cpp +++ b/core/extension/gdnative_interface.cpp @@ -251,27 +251,6 @@ static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self) return self->booleanize(); } -static void gdnative_variant_sub(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst) { - const Variant *a = (const Variant *)p_a; - const Variant *b = (const Variant *)p_b; - memnew_placement(r_dst, Variant); - Variant::sub(*a, *b, *(Variant *)r_dst); -} - -static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) { - const Variant *a = (const Variant *)p_a; - const Variant *b = (const Variant *)p_b; - memnew_placement(r_dst, Variant); - Variant::blend(*a, *b, p_c, *(Variant *)r_dst); -} - -static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) { - const Variant *a = (const Variant *)p_a; - const Variant *b = (const Variant *)p_b; - memnew_placement(r_dst, Variant); - Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst); -} - static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) { const Variant *self = (const Variant *)p_self; memnew_placement(r_ret, Variant(self->duplicate(p_deep))); @@ -905,7 +884,7 @@ static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_clas MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname)); ERR_FAIL_COND_V(!mb, nullptr); if (mb->get_hash() != p_hash) { - ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'."); + ERR_PRINT("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'."); return nullptr; } // MethodBind *mb = ClassDB::get_method("Node", "get_name"); @@ -970,9 +949,6 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) { gdni.variant_recursive_hash = gdnative_variant_recursive_hash; gdni.variant_hash_compare = gdnative_variant_hash_compare; gdni.variant_booleanize = gdnative_variant_booleanize; - gdni.variant_sub = gdnative_variant_sub; - gdni.variant_blend = gdnative_variant_blend; - gdni.variant_interpolate = gdnative_variant_interpolate; gdni.variant_duplicate = gdnative_variant_duplicate; gdni.variant_stringify = gdnative_variant_stringify; diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h index cb2adcb562..39378d8261 100644 --- a/core/extension/gdnative_interface.h +++ b/core/extension/gdnative_interface.h @@ -427,9 +427,6 @@ typedef struct { GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count); GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other); GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self); - void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst); - void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst); - void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst); void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep); void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret); diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index bed41b8d89..f86dfe8057 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -36,6 +36,8 @@ #include "core/os/os.h" #include "core/templates/local_vector.h" +thread_local Error DirAccess::last_dir_open_error = OK; + String DirAccess::_get_root_path() const { switch (_access_type) { case ACCESS_RESOURCES: @@ -249,6 +251,61 @@ Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) { return da; } +Ref<DirAccess> DirAccess::_open(const String &p_path) { + Error err = OK; + Ref<DirAccess> da = open(p_path, &err); + last_dir_open_error = err; + if (err) { + return Ref<DirAccess>(); + } + return da; +} + +int DirAccess::_get_drive_count() { + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + return d->get_drive_count(); +} + +String DirAccess::get_drive_name(int p_idx) { + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + return d->get_drive(p_idx); +} + +Error DirAccess::make_dir_absolute(const String &p_dir) { + Ref<DirAccess> d = DirAccess::create_for_path(p_dir); + return d->make_dir(p_dir); +} + +Error DirAccess::make_dir_recursive_absolute(const String &p_dir) { + Ref<DirAccess> d = DirAccess::create_for_path(p_dir); + return d->make_dir_recursive(p_dir); +} + +bool DirAccess::dir_exists_absolute(const String &p_dir) { + Ref<DirAccess> d = DirAccess::create_for_path(p_dir); + return d->dir_exists(p_dir); +} + +Error DirAccess::copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags) { + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + // Support copying from res:// to user:// etc. + String from = ProjectSettings::get_singleton()->globalize_path(p_from); + String to = ProjectSettings::get_singleton()->globalize_path(p_to); + return d->copy(from, to, p_chmod_flags); +} + +Error DirAccess::rename_absolute(const String &p_from, const String &p_to) { + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + String from = ProjectSettings::get_singleton()->globalize_path(p_from); + String to = ProjectSettings::get_singleton()->globalize_path(p_to); + return d->rename(from, to); +} + +Error DirAccess::remove_absolute(const String &p_path) { + Ref<DirAccess> d = DirAccess::create_for_path(p_path); + return d->remove(p_path); +} + Ref<DirAccess> DirAccess::create(AccessType p_access) { Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr; if (da.is_valid()) { @@ -266,6 +323,10 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) { return da; } +Error DirAccess::get_open_error() { + return last_dir_open_error; +} + String DirAccess::get_full_path(const String &p_path, AccessType p_access) { Ref<DirAccess> d = DirAccess::create(p_access); if (d.is_null()) { @@ -424,3 +485,102 @@ bool DirAccess::exists(String p_dir) { Ref<DirAccess> da = DirAccess::create_for_path(p_dir); return da->change_dir(p_dir) == OK; } + +PackedStringArray DirAccess::get_files() { + return _get_contents(false); +} + +PackedStringArray DirAccess::get_files_at(const String &p_path) { + Ref<DirAccess> da = DirAccess::open(p_path); + return da->get_files(); +} + +PackedStringArray DirAccess::get_directories() { + return _get_contents(true); +} + +PackedStringArray DirAccess::get_directories_at(const String &p_path) { + Ref<DirAccess> da = DirAccess::open(p_path); + return da->get_directories(); +} + +PackedStringArray DirAccess::_get_contents(bool p_directories) { + PackedStringArray ret; + + list_dir_begin(); + String s = _get_next(); + while (!s.is_empty()) { + if (current_is_dir() == p_directories) { + ret.append(s); + } + s = _get_next(); + } + + ret.sort(); + return ret; +} + +String DirAccess::_get_next() { + String next = get_next(); + while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && current_is_hidden()))) { + next = get_next(); + } + return next; +} + +void DirAccess::set_include_navigational(bool p_enable) { + include_navigational = p_enable; +} + +bool DirAccess::get_include_navigational() const { + return include_navigational; +} + +void DirAccess::set_include_hidden(bool p_enable) { + include_hidden = p_enable; +} + +bool DirAccess::get_include_hidden() const { + return include_hidden; +} + +void DirAccess::_bind_methods() { + ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open); + ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error); + + ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next); + ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir); + ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end); + ClassDB::bind_method(D_METHOD("get_files"), &DirAccess::get_files); + ClassDB::bind_static_method("DirAccess", D_METHOD("get_files_at", "path"), &DirAccess::get_files_at); + ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories); + ClassDB::bind_static_method("DirAccess", D_METHOD("get_directories_at", "path"), &DirAccess::get_directories_at); + ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_count"), &DirAccess::_get_drive_count); + ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::get_drive_name); + ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive); + ClassDB::bind_method(D_METHOD("change_dir", "to_dir"), &DirAccess::change_dir); + ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("make_dir", "path"), &DirAccess::make_dir); + ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_absolute", "path"), &DirAccess::make_dir_absolute); + ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &DirAccess::make_dir_recursive); + ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_recursive_absolute", "path"), &DirAccess::make_dir_recursive_absolute); + ClassDB::bind_method(D_METHOD("file_exists", "path"), &DirAccess::file_exists); + ClassDB::bind_method(D_METHOD("dir_exists", "path"), &DirAccess::dir_exists); + ClassDB::bind_static_method("DirAccess", D_METHOD("dir_exists_absolute", "path"), &DirAccess::dir_exists_absolute); + ClassDB::bind_method(D_METHOD("get_space_left"), &DirAccess::get_space_left); + ClassDB::bind_method(D_METHOD("copy", "from", "to", "chmod_flags"), &DirAccess::copy, DEFVAL(-1)); + ClassDB::bind_static_method("DirAccess", D_METHOD("copy_absolute", "from", "to", "chmod_flags"), &DirAccess::copy_absolute, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("rename", "from", "to"), &DirAccess::rename); + ClassDB::bind_static_method("DirAccess", D_METHOD("rename_absolute", "from", "to"), &DirAccess::rename_absolute); + ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove); + ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute); + + ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational); + ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational); + ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden); + ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden"); +} diff --git a/core/io/dir_access.h b/core/io/dir_access.h index 2469c2a080..ee675f1c89 100644 --- a/core/io/dir_access.h +++ b/core/io/dir_access.h @@ -37,6 +37,8 @@ //@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies class DirAccess : public RefCounted { + GDCLASS(DirAccess, RefCounted); + public: enum AccessType { ACCESS_RESOURCES, @@ -53,7 +55,13 @@ private: Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links); + thread_local static Error last_dir_open_error; + bool include_navigational = false; + bool include_hidden = false; + protected: + static void _bind_methods(); + String _get_root_path() const; virtual String _get_root_string() const; @@ -118,6 +126,7 @@ public: static Ref<DirAccess> create_for_path(const String &p_path); static Ref<DirAccess> create(AccessType p_access); + static Error get_open_error(); template <class T> static void make_default(AccessType p_access) { @@ -125,6 +134,30 @@ public: } static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr); + static Ref<DirAccess> _open(const String &p_path); + + static int _get_drive_count(); + static String get_drive_name(int p_idx); + + static Error make_dir_absolute(const String &p_dir); + static Error make_dir_recursive_absolute(const String &p_dir); + static bool dir_exists_absolute(const String &p_dir); + + static Error copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags = -1); + static Error rename_absolute(const String &p_from, const String &p_to); + static Error remove_absolute(const String &p_path); + + PackedStringArray get_files(); + static PackedStringArray get_files_at(const String &p_path); + PackedStringArray get_directories(); + static PackedStringArray get_directories_at(const String &p_path); + PackedStringArray _get_contents(bool p_directories); + String _get_next(); + + void set_include_navigational(bool p_enable); + bool get_include_navigational() const; + void set_include_hidden(bool p_enable); + bool get_include_hidden() const; DirAccess() {} virtual ~DirAccess() {} diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 72c00bd678..499f083f51 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -32,6 +32,8 @@ #include "core/config/project_settings.h" #include "core/crypto/crypto_core.h" +#include "core/io/file_access_compressed.h" +#include "core/io/file_access_encrypted.h" #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" #include "core/os/os.h" @@ -41,6 +43,7 @@ FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr; bool FileAccess::backup_save = false; +thread_local Error FileAccess::last_file_open_error = OK; Ref<FileAccess> FileAccess::create(AccessType p_access) { ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr); @@ -81,7 +84,7 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) { } Error FileAccess::reopen(const String &p_path, int p_mode_flags) { - return _open(p_path, p_mode_flags); + return open_internal(p_path, p_mode_flags); } Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) { @@ -99,7 +102,7 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error * } ret = create_for_path(p_path); - Error err = ret->_open(p_path, p_mode_flags); + Error err = ret->open_internal(p_path, p_mode_flags); if (r_error) { *r_error = err; @@ -111,6 +114,66 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error * return ret; } +Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags) { + Error err = OK; + Ref<FileAccess> fa = open(p_path, p_mode_flags, &err); + last_file_open_error = err; + if (err) { + return Ref<FileAccess>(); + } + return fa; +} + +Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) { + Ref<FileAccess> fa = _open(p_path, p_mode_flags); + if (fa.is_null()) { + return fa; + } + + Ref<FileAccessEncrypted> fae; + fae.instantiate(); + Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); + if (err) { + last_file_open_error = err; + return Ref<FileAccess>(); + } + return fae; +} + +Ref<FileAccess> FileAccess::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) { + Ref<FileAccess> fa = _open(p_path, p_mode_flags); + if (fa.is_null()) { + return fa; + } + + Ref<FileAccessEncrypted> fae; + fae.instantiate(); + Error err = fae->open_and_parse_password(fa, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); + if (err) { + last_file_open_error = err; + return Ref<FileAccess>(); + } + return fae; +} + +Ref<FileAccess> FileAccess::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) { + Ref<FileAccessCompressed> fac; + fac.instantiate(); + fac->configure("GCPF", (Compression::Mode)p_compress_mode); + Error err = fac->open_internal(p_path, p_mode_flags); + + if (err) { + last_file_open_error = err; + return Ref<FileAccess>(); + } + + return fac; +} + +Error FileAccess::get_open_error() { + return last_file_open_error; +} + FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) { return create_func[p_access]; } @@ -227,6 +290,20 @@ 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); + ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant()); + + const uint8_t *r = buff.ptr(); + + Variant v; + Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects); + ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant."); + + return v; +} + double FileAccess::get_double() const { MarshallDouble m; m.l = get_64(); @@ -370,6 +447,17 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const { return strings; } +String FileAccess::get_as_text(bool p_skip_cr) const { + uint64_t original_pos = get_position(); + const_cast<FileAccess *>(this)->seek(0); + + String text = get_as_utf8_string(p_skip_cr); + + const_cast<FileAccess *>(this)->seek(original_pos); + + return text; +} + uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); @@ -381,6 +469,27 @@ 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> data; + + ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0."); + if (p_length == 0) { + return data; + } + + Error err = data.resize(p_length); + ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements."); + + uint8_t *w = data.ptrw(); + int64_t len = get_buffer(&w[0], p_length); + + if (len < p_length) { + data.resize(len); + } + + return data; +} + String FileAccess::get_as_utf8_string(bool p_skip_cr) const { Vector<uint8_t> sourcef; uint64_t len = get_length(); @@ -554,6 +663,33 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { } } +void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) { + uint64_t len = p_buffer.size(); + if (len == 0) { + return; + } + + const uint8_t *r = p_buffer.ptr(); + + store_buffer(&r[0], len); +} + +void FileAccess::store_var(const Variant &p_var, bool p_full_objects) { + int len; + Error err = encode_variant(p_var, nullptr, len, p_full_objects); + ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); + + Vector<uint8_t> buff; + buff.resize(len); + + uint8_t *w = buff.ptrw(); + err = encode_variant(p_var, &w[0], len, p_full_objects); + ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); + + store_32(len); + _store_buffer(buff); +} + Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) { Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error); if (f.is_null()) { @@ -666,3 +802,69 @@ String FileAccess::get_sha256(const String &p_file) { return String::hex_encode_buffer(hash, 32); } + +void FileAccess::_bind_methods() { + ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open); + ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted); + ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass); + ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0)); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error); + + ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush); + ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path); + ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute); + ClassDB::bind_method(D_METHOD("is_open"), &FileAccess::is_open); + ClassDB::bind_method(D_METHOD("seek", "position"), &FileAccess::seek); + ClassDB::bind_method(D_METHOD("seek_end", "position"), &FileAccess::seek_end, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_position"), &FileAccess::get_position); + ClassDB::bind_method(D_METHOD("get_length"), &FileAccess::get_length); + ClassDB::bind_method(D_METHOD("eof_reached"), &FileAccess::eof_reached); + ClassDB::bind_method(D_METHOD("get_8"), &FileAccess::get_8); + ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16); + ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32); + ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64); + 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_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)); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_md5", "path"), &FileAccess::get_md5); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_sha256", "path"), &FileAccess::get_sha256); + ClassDB::bind_method(D_METHOD("is_big_endian"), &FileAccess::is_big_endian); + ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &FileAccess::set_big_endian); + ClassDB::bind_method(D_METHOD("get_error"), &FileAccess::get_error); + ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &FileAccess::get_var, DEFVAL(false)); + + ClassDB::bind_method(D_METHOD("store_8", "value"), &FileAccess::store_8); + ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16); + ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32); + ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64); + 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_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); + ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var, DEFVAL(false)); + + ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string); + ClassDB::bind_method(D_METHOD("get_pascal_string"), &FileAccess::get_pascal_string); + + ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian"); + + BIND_ENUM_CONSTANT(READ); + BIND_ENUM_CONSTANT(WRITE); + BIND_ENUM_CONSTANT(READ_WRITE); + BIND_ENUM_CONSTANT(WRITE_READ); + + BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ); + BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE); + BIND_ENUM_CONSTANT(COMPRESSION_ZSTD); + BIND_ENUM_CONSTANT(COMPRESSION_GZIP); +} diff --git a/core/io/file_access.h b/core/io/file_access.h index fc0eb95d44..f8c42d3c0d 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -31,6 +31,7 @@ #ifndef FILE_ACCESS_H #define FILE_ACCESS_H +#include "core/io/compression.h" #include "core/math/math_defs.h" #include "core/object/ref_counted.h" #include "core/os/memory.h" @@ -42,6 +43,8 @@ */ class FileAccess : public RefCounted { + GDCLASS(FileAccess, RefCounted); + public: enum AccessType { ACCESS_RESOURCES, @@ -60,15 +63,18 @@ public: virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0; protected: + static void _bind_methods(); + AccessType get_access_type() const; String fix_path(const String &p_path) const; - virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file + virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file virtual uint64_t _get_modified_time(const String &p_file) = 0; static FileCloseFailNotify close_fail_notify; private: static bool backup_save; + thread_local static Error last_file_open_error; AccessType _access_type = ACCESS_FILESYSTEM; static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */ @@ -89,6 +95,13 @@ public: WRITE_READ = 7, }; + enum CompressionMode { + COMPRESSION_FASTLZ = Compression::MODE_FASTLZ, + COMPRESSION_DEFLATE = Compression::MODE_DEFLATE, + COMPRESSION_ZSTD = Compression::MODE_ZSTD, + COMPRESSION_GZIP = Compression::MODE_GZIP + }; + virtual bool is_open() const = 0; ///< true when file is open virtual String get_path() const { return ""; } /// returns the path for the current open file @@ -110,10 +123,14 @@ public: virtual double get_double() const; virtual real_t get_real() const; + 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; virtual String get_line() const; virtual String get_token() const; virtual Vector<String> get_csv_line(const String &p_delim = ",") const; + String get_as_text(bool p_skip_cr = false) const; virtual String get_as_utf8_string(bool p_skip_cr = false) const; /** @@ -144,6 +161,9 @@ 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_var(const Variant &p_var, bool p_full_objects = false); virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists @@ -152,6 +172,13 @@ public: static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. static Ref<FileAccess> create_for_path(const String &p_path); static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files. + + static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags); + static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key); + static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass); + static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ); + static Error get_open_error(); + static CreateFunc get_create_func(AccessType p_access); static bool exists(const String &p_name); ///< return true if a file exists static uint64_t get_modified_time(const String &p_file); @@ -177,4 +204,7 @@ public: virtual ~FileAccess() {} }; +VARIANT_ENUM_CAST(FileAccess::CompressionMode); +VARIANT_ENUM_CAST(FileAccess::ModeFlags); + #endif // FILE_ACCESS_H diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 1d0a718166..d2c8a88269 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -95,7 +95,7 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) { return ret == -1 ? ERR_FILE_CORRUPT : OK; } -Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { +Error FileAccessCompressed::open_internal(const String &p_path, int p_mode_flags) { ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE); _close(); diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index e41491a92c..ee114c2c65 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -70,7 +70,7 @@ public: Error open_after_magic(Ref<FileAccess> p_base); - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual void seek(uint64_t p_position) override; ///< seek to a given position diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index d1b014a0be..be502dacd9 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -111,7 +111,7 @@ Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const return open_and_parse(p_base, key, p_mode); } -Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) { +Error FileAccessEncrypted::open_internal(const String &p_path, int p_mode_flags) { return OK; } diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 6200f87a7a..6b4588841d 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -60,7 +60,7 @@ public: Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true); Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode); - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual String get_path() const override; /// returns the path for the current open file diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 499d001234..21ded4247f 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -78,7 +78,7 @@ Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) { return OK; } -Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) { +Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) { ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND); String name = fix_path(p_path); diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index f2bd2aa832..b1f408eb98 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -45,7 +45,7 @@ public: static void cleanup(); virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual void seek(uint64_t p_position) override; ///< seek to a given position diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 1365b4b593..13730518bf 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -252,7 +252,7 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) { pages.resize(pc); } -Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) { +Error FileAccessNetwork::open_internal(const String &p_path, int p_mode_flags) { ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE); _close(); diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index ceadc715a1..ee92d3b9db 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -132,7 +132,7 @@ public: RESPONSE_GET_MODTIME, }; - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual void seek(uint64_t p_position) override; ///< seek to a given position diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index adae0db0f4..dfcce30ab5 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -259,7 +259,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack ////////////////////////////////////////////////////////////////// -Error FileAccessPack::_open(const String &p_path, int p_mode_flags) { +Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) { ERR_FAIL_V(ERR_UNAVAILABLE); return ERR_UNAVAILABLE; } diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 023758ac0f..4b9b49a161 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -148,7 +148,7 @@ class FileAccessPack : public FileAccess { uint64_t off; Ref<FileAccess> f; - virtual Error _open(const String &p_path, int p_mode_flags) override; + virtual Error open_internal(const String &p_path, int p_mode_flags) override; virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; } virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; } diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 17f2335a8e..2af6f370cf 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -234,7 +234,7 @@ ZipArchive::~ZipArchive() { packages.clear(); } -Error FileAccessZip::_open(const String &p_path, int p_mode_flags) { +Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) { _close(); ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED); diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index 74a48192f3..6d61b9a291 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -85,7 +85,7 @@ class FileAccessZip : public FileAccess { void _close(); public: - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual void seek(uint64_t p_position) override; ///< seek to a given position diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index d09697b951..d6854666c0 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -32,6 +32,12 @@ #include "core/string/print_string.h" +void ImageFormatLoader::_bind_methods() { + BIND_BITFIELD_FLAG(FLAG_NONE); + BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR); + BIND_BITFIELD_FLAG(FLAG_CONVERT_COLORS); +} + bool ImageFormatLoader::recognize(const String &p_extension) const { List<String> extensions; get_recognized_extensions(&extensions); @@ -44,7 +50,39 @@ bool ImageFormatLoader::recognize(const String &p_extension) const { return false; } -Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) { +Error ImageFormatLoaderExtension::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { + Error err; + if (GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err)) { + return err; + } + return ERR_UNAVAILABLE; +} + +void ImageFormatLoaderExtension::get_recognized_extensions(List<String> *p_extension) const { + PackedStringArray ext; + if (GDVIRTUAL_CALL(_get_recognized_extensions, ext)) { + for (int i = 0; i < ext.size(); i++) { + p_extension->push_back(ext[i]); + } + } +} + +void ImageFormatLoaderExtension::add_format_loader() { + ImageLoader::add_image_format_loader(this); +} + +void ImageFormatLoaderExtension::remove_format_loader() { + ImageLoader::remove_image_format_loader(this); +} + +void ImageFormatLoaderExtension::_bind_methods() { + GDVIRTUAL_BIND(_get_recognized_extensions); + GDVIRTUAL_BIND(_load_image, "image", "fileaccess", "flags", "scale"); + ClassDB::bind_method(D_METHOD("add_format_loader"), &ImageFormatLoaderExtension::add_format_loader); + ClassDB::bind_method(D_METHOD("remove_format_loader"), &ImageFormatLoaderExtension::remove_format_loader); +} + +Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object."); Ref<FileAccess> f = p_custom; @@ -60,7 +98,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> if (!loader[i]->recognize(extension)) { continue; } - Error err = loader[i]->load_image(p_image, f, p_flags, p_scale); + Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale); if (err != OK) { ERR_PRINT("Error loading image: " + p_file); } @@ -79,7 +117,7 @@ void ImageLoader::get_recognized_extensions(List<String> *p_extensions) { } } -ImageFormatLoader *ImageLoader::recognize(const String &p_extension) { +Ref<ImageFormatLoader> ImageLoader::recognize(const String &p_extension) { for (int i = 0; i < loader.size(); i++) { if (loader[i]->recognize(p_extension)) { return loader[i]; @@ -89,17 +127,17 @@ ImageFormatLoader *ImageLoader::recognize(const String &p_extension) { return nullptr; } -Vector<ImageFormatLoader *> ImageLoader::loader; +Vector<Ref<ImageFormatLoader>> ImageLoader::loader; -void ImageLoader::add_image_format_loader(ImageFormatLoader *p_loader) { +void ImageLoader::add_image_format_loader(Ref<ImageFormatLoader> p_loader) { loader.push_back(p_loader); } -void ImageLoader::remove_image_format_loader(ImageFormatLoader *p_loader) { +void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) { loader.erase(p_loader); } -const Vector<ImageFormatLoader *> &ImageLoader::get_image_format_loaders() { +const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() { return loader; } @@ -152,7 +190,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String Ref<Image> image; image.instantiate(); - Error err = ImageLoader::loader[idx]->load_image(image, f); + Error err = ImageLoader::loader.write[idx]->load_image(image, f); if (err != OK) { if (r_error) { diff --git a/core/io/image_loader.h b/core/io/image_loader.h index bf78005e40..f70fdf22aa 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -31,23 +31,23 @@ #ifndef IMAGE_LOADER_H #define IMAGE_LOADER_H +#include "core/core_bind.h" #include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" +#include "core/object/gdvirtual.gen.inc" #include "core/string/ustring.h" #include "core/templates/list.h" +#include "core/variant/binder_common.h" class ImageLoader; -class ImageFormatLoader { +class ImageFormatLoader : public RefCounted { + GDCLASS(ImageFormatLoader, RefCounted); + friend class ImageLoader; friend class ResourceFormatLoaderImage; -protected: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0; - virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; - bool recognize(const String &p_extension) const; - public: enum LoaderFlags { FLAG_NONE = 0, @@ -55,23 +55,50 @@ public: FLAG_CONVERT_COLORS = 2, }; +protected: + static void _bind_methods(); + + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) = 0; + virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; + bool recognize(const String &p_extension) const; + +public: virtual ~ImageFormatLoader() {} }; +VARIANT_BITFIELD_CAST(ImageFormatLoader::LoaderFlags); + +class ImageFormatLoaderExtension : public ImageFormatLoader { + GDCLASS(ImageFormatLoaderExtension, ImageFormatLoader); + +protected: + static void _bind_methods(); + +public: + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + + void add_format_loader(); + void remove_format_loader(); + + GDVIRTUAL0RC(PackedStringArray, _get_recognized_extensions); + GDVIRTUAL4R(Error, _load_image, Ref<Image>, Ref<FileAccess>, BitField<ImageFormatLoader::LoaderFlags>, float); +}; + class ImageLoader { - static Vector<ImageFormatLoader *> loader; + static Vector<Ref<ImageFormatLoader>> loader; friend class ResourceFormatLoaderImage; protected: public: - static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0); + static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), BitField<ImageFormatLoader::LoaderFlags> p_flags = ImageFormatLoader::FLAG_NONE, float p_scale = 1.0); static void get_recognized_extensions(List<String> *p_extensions); - static ImageFormatLoader *recognize(const String &p_extension); + static Ref<ImageFormatLoader> recognize(const String &p_extension); - static void add_image_format_loader(ImageFormatLoader *p_loader); - static void remove_image_format_loader(ImageFormatLoader *p_loader); + static void add_image_format_loader(Ref<ImageFormatLoader> p_loader); + static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader); - static const Vector<ImageFormatLoader *> &get_image_format_loaders(); + 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 91500ff3d5..7e267d35d4 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -56,6 +56,8 @@ String JSON::_make_indent(const String &p_indent, int p_size) { } String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) { + ERR_FAIL_COND_V_MSG(p_cur_indent > Variant::MAX_RECURSION_DEPTH, "...", "JSON structure is too deep. Bailing."); + String colon = ":"; String end_statement = ""; @@ -357,17 +359,22 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to return ERR_PARSE_ERROR; } -Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) { +Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) { + if (p_depth > Variant::MAX_RECURSION_DEPTH) { + r_err_str = "JSON structure is too deep. Bailing."; + return ERR_OUT_OF_MEMORY; + } + if (token.type == TK_CURLY_BRACKET_OPEN) { Dictionary d; - Error err = _parse_object(d, p_str, index, p_len, line, r_err_str); + Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str); if (err) { return err; } value = d; } else if (token.type == TK_BRACKET_OPEN) { Array a; - Error err = _parse_array(a, p_str, index, p_len, line, r_err_str); + Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str); if (err) { return err; } @@ -396,7 +403,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in return OK; } -Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) { +Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) { Token token; bool need_comma = false; @@ -421,7 +428,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_ } Variant v; - err = _parse_value(v, token, p_str, index, p_len, line, r_err_str); + err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str); if (err) { return err; } @@ -434,7 +441,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_ return ERR_PARSE_ERROR; } -Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) { +Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) { bool at_key = true; String key; Token token; @@ -483,7 +490,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, } Variant v; - err = _parse_value(v, token, p_str, index, p_len, line, r_err_str); + err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str); if (err) { return err; } @@ -497,6 +504,10 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, return ERR_PARSE_ERROR; } +void JSON::set_data(const Variant &p_data) { + data = p_data; +} + Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { const char32_t *str = p_json.ptr(); int idx = 0; @@ -510,7 +521,7 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st return err; } - err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str); + err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str); // Check if EOF is reached // or it's a type of the next token. @@ -557,6 +568,88 @@ void JSON::_bind_methods() { ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); 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_error_line"), &JSON::get_error_line); ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message); + + ADD_PROPERTY(PropertyInfo(Variant::NIL, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), "set_data", "get_data"); // Ensures that it can be serialized as binary. +} + +//// + +//////////// + +Ref<Resource> ResourceFormatLoaderJSON::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; + } + + if (!FileAccess::exists(p_path)) { + *r_error = ERR_FILE_NOT_FOUND; + return Ref<Resource>(); + } + + Ref<JSON> json; + json.instantiate(); + + Error err = json->parse(FileAccess::get_file_as_string(p_path)); + if (err != OK) { + if (r_error) { + *r_error = err; + } + 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) { + *r_error = OK; + } + + return json; +} + +void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("json"); +} + +bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const { + return (p_type == "JSON"); +} + +String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "json") { + return "JSON"; + } + return ""; +} + +Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) { + 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); + + Error err; + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + ERR_FAIL_COND_V_MSG(err, err, "Cannot save json '" + p_path + "'."); + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } + + return OK; +} + +void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const { + Ref<JSON> json = p_resource; + if (json.is_valid()) { + p_extensions->push_back("json"); + } +} + +bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const { + return p_resource->get_class_name() == "JSON"; //only json, not inherited } diff --git a/core/io/json.h b/core/io/json.h index 840b1cc08a..829a5f922b 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -31,7 +31,9 @@ #ifndef JSON_H #define JSON_H -#include "core/object/ref_counted.h" +#include "core/io/resource.h" +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" #include "core/variant/variant.h" class JSON : public RefCounted { @@ -72,9 +74,9 @@ class JSON : public RefCounted { static String _make_indent(const String &p_indent, int p_size); static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision = false); static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); - static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); - static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); - static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); + static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str); + static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str); + static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str); static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); protected: @@ -86,8 +88,24 @@ public: static Variant parse_string(const String &p_json_string); inline Variant get_data() const { return data; } + void set_data(const Variant &p_data); inline int get_error_line() const { return err_line; } inline String get_error_message() const { return err_str; } }; +class ResourceFormatLoaderJSON : public ResourceFormatLoader { +public: + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + 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; +}; + +class ResourceFormatSaverJSON : public ResourceFormatSaver { +public: + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const Ref<Resource> &p_resource) const; +}; + #endif // JSON_H diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 4f1204fc48..06649aba5b 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1206,7 +1206,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons Ref<FileAccessCompressed> facw; facw.instantiate(); facw->configure("RSCC"); - err = facw->_open(p_path + ".depren", FileAccess::WRITE); + err = facw->open_internal(p_path + ".depren", FileAccess::WRITE); ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'."); fw = facw; @@ -1986,7 +1986,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re fac.instantiate(); fac->configure("RSCC"); f = fac; - err = fac->_open(p_path, FileAccess::WRITE); + err = fac->open_internal(p_path, FileAccess::WRITE); } else { f = FileAccess::open(p_path, FileAccess::WRITE, &err); } diff --git a/core/io/stream_peer_gzip.cpp b/core/io/stream_peer_gzip.cpp new file mode 100644 index 0000000000..ca8be2d62e --- /dev/null +++ b/core/io/stream_peer_gzip.cpp @@ -0,0 +1,209 @@ +/*************************************************************************/ +/* stream_peer_gzip.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/io/stream_peer_gzip.h" + +#include "core/io/zip_io.h" +#include <zlib.h> + +void StreamPeerGZIP::_bind_methods() { + ClassDB::bind_method(D_METHOD("start_compression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_compression, DEFVAL(false), DEFVAL(65535)); + ClassDB::bind_method(D_METHOD("start_decompression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_decompression, DEFVAL(false), DEFVAL(65535)); + ClassDB::bind_method(D_METHOD("finish"), &StreamPeerGZIP::finish); + ClassDB::bind_method(D_METHOD("clear"), &StreamPeerGZIP::clear); +} + +StreamPeerGZIP::StreamPeerGZIP() { +} + +StreamPeerGZIP::~StreamPeerGZIP() { + _close(); +} + +void StreamPeerGZIP::_close() { + if (ctx) { + z_stream *strm = (z_stream *)ctx; + if (compressing) { + deflateEnd(strm); + } else { + inflateEnd(strm); + } + memfree(strm); + ctx = nullptr; + } +} + +void StreamPeerGZIP::clear() { + _close(); + rb.clear(); + buffer.clear(); +} + +Error StreamPeerGZIP::start_compression(bool p_is_deflate, int buffer_size) { + return _start(true, p_is_deflate, buffer_size); +} + +Error StreamPeerGZIP::start_decompression(bool p_is_deflate, int buffer_size) { + return _start(false, p_is_deflate, buffer_size); +} + +Error StreamPeerGZIP::_start(bool p_compress, bool p_is_deflate, int buffer_size) { + ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE); + clear(); + compressing = p_compress; + rb.resize(nearest_shift(buffer_size - 1)); + buffer.resize(1024); + + // Create ctx. + ctx = memalloc(sizeof(z_stream)); + z_stream &strm = *(z_stream *)ctx; + strm.next_in = Z_NULL; + strm.avail_in = 0; + strm.zalloc = zipio_alloc; + strm.zfree = zipio_free; + strm.opaque = Z_NULL; + int window_bits = p_is_deflate ? 15 : (15 + 16); + int err = Z_OK; + int level = Z_DEFAULT_COMPRESSION; + if (compressing) { + err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY); + } else { + err = inflateInit2(&strm, window_bits); + } + ERR_FAIL_COND_V(err != Z_OK, FAILED); + return OK; +} + +Error StreamPeerGZIP::_process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close) { + ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED); + z_stream &strm = *(z_stream *)ctx; + strm.avail_in = p_src_size; + strm.avail_out = p_dst_size; + strm.next_in = (Bytef *)p_src; + strm.next_out = (Bytef *)p_dst; + int flush = p_close ? Z_FINISH : Z_NO_FLUSH; + if (compressing) { + int err = deflate(&strm, flush); + ERR_FAIL_COND_V(err != (p_close ? Z_STREAM_END : Z_OK), FAILED); + } else { + int err = inflate(&strm, flush); + ERR_FAIL_COND_V(err != Z_OK && err != Z_STREAM_END, FAILED); + } + r_out = p_dst_size - strm.avail_out; + r_consumed = p_src_size - strm.avail_in; + return OK; +} + +Error StreamPeerGZIP::put_data(const uint8_t *p_data, int p_bytes) { + int wrote = 0; + Error err = put_partial_data(p_data, p_bytes, wrote); + if (err != OK) { + return err; + } + ERR_FAIL_COND_V(p_bytes != wrote, ERR_OUT_OF_MEMORY); + return OK; +} + +Error StreamPeerGZIP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { + ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED); + ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER); + + // Ensure we have enough space in temporary buffer. + if (buffer.size() < p_bytes) { + buffer.resize(p_bytes); + } + + r_sent = 0; + while (r_sent < p_bytes && rb.space_left() > 1024) { // Keep the ring buffer size meaningful. + int sent = 0; + int to_write = 0; + // Compress or decompress + Error err = _process(buffer.ptrw(), MIN(buffer.size(), rb.space_left()), p_data + r_sent, p_bytes - r_sent, sent, to_write); + if (err != OK) { + return err; + } + // When decompressing, we might need to do another round. + r_sent += sent; + + // We can't write more than this buffer is full. + if (sent == 0 && to_write == 0) { + return OK; + } + if (to_write) { + // Copy to ring buffer. + int wrote = rb.write(buffer.ptr(), to_write); + ERR_FAIL_COND_V(wrote != to_write, ERR_BUG); + } + } + return OK; +} + +Error StreamPeerGZIP::get_data(uint8_t *p_buffer, int p_bytes) { + int received = 0; + Error err = get_partial_data(p_buffer, p_bytes, received); + if (err != OK) { + return err; + } + ERR_FAIL_COND_V(p_bytes != received, ERR_UNAVAILABLE); + return OK; +} + +Error StreamPeerGZIP::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { + ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER); + + r_received = MIN(p_bytes, rb.data_left()); + if (r_received == 0) { + return OK; + } + int received = rb.read(p_buffer, r_received); + ERR_FAIL_COND_V(received != r_received, ERR_BUG); + return OK; +} + +int StreamPeerGZIP::get_available_bytes() const { + return rb.data_left(); +} + +Error StreamPeerGZIP::finish() { + ERR_FAIL_COND_V(!ctx || !compressing, ERR_UNAVAILABLE); + // Ensure we have enough space in temporary buffer. + if (buffer.size() < 1024) { + buffer.resize(1024); // 1024 should be more than enough. + } + int consumed = 0; + int to_write = 0; + Error err = _process(buffer.ptrw(), 1024, nullptr, 0, consumed, to_write, true); // compress + if (err != OK) { + return err; + } + int wrote = rb.write(buffer.ptr(), to_write); + ERR_FAIL_COND_V(wrote != to_write, ERR_OUT_OF_MEMORY); + return OK; +} diff --git a/core/io/stream_peer_gzip.h b/core/io/stream_peer_gzip.h new file mode 100644 index 0000000000..5bafdbca9b --- /dev/null +++ b/core/io/stream_peer_gzip.h @@ -0,0 +1,76 @@ +/*************************************************************************/ +/* stream_peer_gzip.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef STREAM_PEER_GZIP_H +#define STREAM_PEER_GZIP_H + +#include "core/io/stream_peer.h" + +#include "core/core_bind.h" +#include "core/io/compression.h" +#include "core/templates/ring_buffer.h" + +class StreamPeerGZIP : public StreamPeer { + GDCLASS(StreamPeerGZIP, StreamPeer); + +private: + void *ctx = nullptr; // Will hold our z_stream instance. + bool compressing = true; + + RingBuffer<uint8_t> rb; + Vector<uint8_t> buffer; + + Error _process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close = false); + void _close(); + Error _start(bool p_compress, bool p_is_deflate, int buffer_size = 65535); + +protected: + static void _bind_methods(); + +public: + Error start_compression(bool p_is_deflate, int buffer_size = 65535); + Error start_decompression(bool p_is_deflate, int buffer_size = 65535); + + Error finish(); + void clear(); + + virtual Error put_data(const uint8_t *p_data, int p_bytes) override; + virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override; + + virtual Error get_data(uint8_t *p_buffer, int p_bytes) override; + virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override; + + virtual int get_available_bytes() const override; + + StreamPeerGZIP(); + ~StreamPeerGZIP(); +}; + +#endif // STREAM_PEER_GZIP_H diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 0eb6320ac6..4b163409ce 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -754,29 +754,28 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { #ifdef MATH_CHECKS ERR_FAIL_COND(!is_rotation()); #endif -*/ - real_t angle, x, y, z; // variables for result - real_t angle_epsilon = 0.1; // margin to distinguish between 0 and 180 degrees - - if ((Math::abs(rows[1][0] - rows[0][1]) < CMP_EPSILON) && (Math::abs(rows[2][0] - rows[0][2]) < CMP_EPSILON) && (Math::abs(rows[2][1] - rows[1][2]) < CMP_EPSILON)) { - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms - if ((Math::abs(rows[1][0] + rows[0][1]) < angle_epsilon) && (Math::abs(rows[2][0] + rows[0][2]) < angle_epsilon) && (Math::abs(rows[2][1] + rows[1][2]) < angle_epsilon) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < angle_epsilon)) { - // this singularity is identity matrix so angle = 0 + */ + + // https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + real_t x, y, z; // Variables for result. + if (Math::is_zero_approx(rows[0][1] - rows[1][0]) && Math::is_zero_approx(rows[0][2] - rows[2][0]) && Math::is_zero_approx(rows[1][2] - rows[2][1])) { + // Singularity found. + // First check for identity matrix which must have +1 for all terms in leading diagonal and zero in other terms. + if (is_diagonal() && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < 3 * CMP_EPSILON)) { + // This singularity is identity matrix so angle = 0. r_axis = Vector3(0, 1, 0); r_angle = 0; return; } - // otherwise this singularity is angle = 180 - angle = Math_PI; + // Otherwise this singularity is angle = 180. real_t xx = (rows[0][0] + 1) / 2; real_t yy = (rows[1][1] + 1) / 2; real_t zz = (rows[2][2] + 1) / 2; - real_t xy = (rows[1][0] + rows[0][1]) / 4; - real_t xz = (rows[2][0] + rows[0][2]) / 4; - real_t yz = (rows[2][1] + rows[1][2]) / 4; - if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term + real_t xy = (rows[0][1] + rows[1][0]) / 4; + real_t xz = (rows[0][2] + rows[2][0]) / 4; + real_t yz = (rows[1][2] + rows[2][1]) / 4; + + if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term. if (xx < CMP_EPSILON) { x = 0; y = Math_SQRT12; @@ -786,7 +785,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { y = xy / x; z = xz / x; } - } else if (yy > zz) { // rows[1][1] is the largest diagonal term + } else if (yy > zz) { // rows[1][1] is the largest diagonal term. if (yy < CMP_EPSILON) { x = Math_SQRT12; y = 0; @@ -796,7 +795,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { x = xy / y; z = yz / y; } - } else { // rows[2][2] is the largest diagonal term so base result on this + } else { // rows[2][2] is the largest diagonal term so base result on this. if (zz < CMP_EPSILON) { x = Math_SQRT12; y = Math_SQRT12; @@ -808,22 +807,24 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { } } r_axis = Vector3(x, y, z); - r_angle = angle; + r_angle = Math_PI; return; } - // as we have reached here there are no singularities so we can handle normally - real_t s = Math::sqrt((rows[1][2] - rows[2][1]) * (rows[1][2] - rows[2][1]) + (rows[2][0] - rows[0][2]) * (rows[2][0] - rows[0][2]) + (rows[0][1] - rows[1][0]) * (rows[0][1] - rows[1][0])); // s=|axis||sin(angle)|, used to normalise + // As we have reached here there are no singularities so we can handle normally. + double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise. - angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2); - if (angle < 0) { - s = -s; + if (Math::abs(s) < CMP_EPSILON) { + // Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above. + s = 1; } + x = (rows[2][1] - rows[1][2]) / s; y = (rows[0][2] - rows[2][0]) / s; z = (rows[1][0] - rows[0][1]) / s; r_axis = Vector3(x, y, z); - r_angle = angle; + // CLAMP to avoid NaN if the value passed to acos is not in [0,1]. + r_angle = Math::acos(CLAMP((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2, (real_t)0.0, (real_t)1.0)); } void Basis::set_quaternion(const Quaternion &p_quaternion) { diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 656fc9f798..7fa674a23d 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -267,6 +267,7 @@ public: return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight); } + static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) { float from_rot = fmod(p_from, (float)Math_TAU); @@ -293,6 +294,7 @@ public: double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t); return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t); } + static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, float p_to_t, float p_pre_t, float p_post_t) { /* Barry-Goldman method */ @@ -320,6 +322,7 @@ public: return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t); } + static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, float p_to_t, float p_pre_t, float p_post_t) { float from_rot = fmod(p_from, (float)Math_TAU); @@ -346,6 +349,7 @@ public: return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; } + static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { /* Formula from Wikipedia article on Bezier curves. */ float omt = (1.0f - p_t); @@ -368,11 +372,19 @@ public: return p_from + distance * p_weight; } - static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); } - static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); } + static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { + return (p_value - p_from) / (p_to - p_from); + } + static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { + return (p_value - p_from) / (p_to - p_from); + } - static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } - static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); } + static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { + return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); + } + static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { + return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); + } static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) { if (is_equal_approx(p_from, p_to)) { @@ -388,14 +400,26 @@ public: float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); return s * s * (3.0f - 2.0f * s); } - static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; } - static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; } + static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { + return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; + } + static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { + return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; + } - static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; } - static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; } + static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { + return Math::log(p_linear) * 8.6858896380650365530225783783321; + } + static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { + return Math::log(p_linear) * (float)8.6858896380650365530225783783321; + } - static _ALWAYS_INLINE_ double db_to_linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); } - static _ALWAYS_INLINE_ float db_to_linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); } + static _ALWAYS_INLINE_ double db_to_linear(double p_db) { + return Math::exp(p_db * 0.11512925464970228420089957273422); + } + static _ALWAYS_INLINE_ float db_to_linear(float p_db) { + return Math::exp(p_db * (float)0.11512925464970228420089957273422); + } static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); } static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); } diff --git a/core/math/vector2i.h b/core/math/vector2i.h index 0245900a3b..e131bdea94 100644 --- a/core/math/vector2i.h +++ b/core/math/vector2i.h @@ -38,6 +38,8 @@ class String; struct Vector2; struct _NO_DISCARD_ Vector2i { + static const int AXIS_COUNT = 2; + enum Axis { AXIS_X, AXIS_Y, diff --git a/core/math/vector3i.h b/core/math/vector3i.h index 825ce40318..c6d03cd031 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -38,6 +38,8 @@ class String; struct Vector3; struct _NO_DISCARD_ Vector3i { + static const int AXIS_COUNT = 3; + enum Axis { AXIS_X, AXIS_Y, diff --git a/core/math/vector4.h b/core/math/vector4.h index f964264108..d89f3ddb05 100644 --- a/core/math/vector4.h +++ b/core/math/vector4.h @@ -37,6 +37,8 @@ #include "core/string/ustring.h" struct _NO_DISCARD_ Vector4 { + static const int AXIS_COUNT = 4; + enum Axis { AXIS_X, AXIS_Y, diff --git a/core/math/vector4i.h b/core/math/vector4i.h index d08e40d754..fdf33b9569 100644 --- a/core/math/vector4i.h +++ b/core/math/vector4i.h @@ -38,6 +38,8 @@ class String; struct Vector4; struct _NO_DISCARD_ Vector4i { + static const int AXIS_COUNT = 4; + enum Axis { AXIS_X, AXIS_Y, diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index d3c48853f1..aa66e86bc0 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -126,27 +126,28 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { force_keep_in_merge_ends = false; } -void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { - ERR_FAIL_COND(p_object == nullptr); +void UndoRedo::add_do_method(const Callable &p_callable) { + ERR_FAIL_COND(p_callable.is_null()); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); + + Object *object = p_callable.get_object(); + ERR_FAIL_NULL(object); + Operation do_op; - do_op.object = p_object->get_instance_id(); - if (Object::cast_to<RefCounted>(p_object)) { - do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); + do_op.callable = p_callable; + do_op.object = p_callable.get_object_id(); + if (Object::cast_to<RefCounted>(object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object)); } - do_op.type = Operation::TYPE_METHOD; - do_op.name = p_method; + do_op.name = p_callable.get_method(); - for (int i = 0; i < p_argcount; i++) { - do_op.args.push_back(*p_args[i]); - } actions.write[current_action + 1].do_ops.push_back(do_op); } -void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { - ERR_FAIL_COND(p_object == nullptr); +void UndoRedo::add_undo_method(const Callable &p_callable) { + ERR_FAIL_COND(p_callable.is_null()); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -155,19 +156,19 @@ void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, co return; } + Object *object = p_callable.get_object(); + ERR_FAIL_NULL(object); + Operation undo_op; - undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<RefCounted>(p_object)) { - undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); + undo_op.callable = p_callable; + undo_op.object = p_callable.get_object_id(); + if (Object::cast_to<RefCounted>(object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object)); } - undo_op.type = Operation::TYPE_METHOD; undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; - undo_op.name = p_method; + undo_op.name = p_callable.get_method(); - for (int i = 0; i < p_argcount; i++) { - undo_op.args.push_back(*p_args[i]); - } actions.write[current_action + 1].undo_ops.push_back(undo_op); } @@ -183,7 +184,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c do_op.type = Operation::TYPE_PROPERTY; do_op.name = p_property; - do_op.args.push_back(p_value); + do_op.value = p_value; actions.write[current_action + 1].do_ops.push_back(do_op); } @@ -206,7 +207,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, undo_op.type = Operation::TYPE_PROPERTY; undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_property; - undo_op.args.push_back(p_value); + undo_op.value = p_value; actions.write[current_action + 1].undo_ops.push_back(undo_op); } @@ -312,33 +313,42 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { switch (op.type) { case Operation::TYPE_METHOD: { - int argc = op.args.size(); - Vector<const Variant *> argptrs; - argptrs.resize(argc); - - for (int i = 0; i < argc; i++) { - argptrs.write[i] = &op.args[i]; - } - Callable::CallError ce; - obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce); + Variant ret; + op.callable.callp(nullptr, 0, ret, ce); if (ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce)); + ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, nullptr, 0, ce)); } #ifdef TOOLS_ENABLED Resource *res = Object::cast_to<Resource>(obj); if (res) { res->set_edited(true); } - #endif if (method_callback) { - method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc); + Vector<Variant> binds; + if (op.callable.is_custom()) { + CallableCustomBind *ccb = dynamic_cast<CallableCustomBind *>(op.callable.get_custom()); + if (ccb) { + binds = ccb->get_binds(); + } + } + + if (binds.is_empty()) { + method_callback(method_callback_ud, obj, op.name, nullptr, 0); + } else { + const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size()); + for (int i = 0; i < binds.size(); i++) { + args[i] = (const Variant *)&binds[i]; + } + + method_callback(method_callback_ud, obj, op.name, args, binds.size()); + } } } break; case Operation::TYPE_PROPERTY: { - obj->set(op.name, op.args[0]); + obj->set(op.name, op.value); #ifdef TOOLS_ENABLED Resource *res = Object::cast_to<Resource>(obj); if (res) { @@ -346,7 +356,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { } #endif if (property_callback) { - property_callback(prop_callback_ud, obj, op.name, op.args[0]); + property_callback(prop_callback_ud, obj, op.name, op.value); } } break; case Operation::TYPE_REFERENCE: { @@ -444,87 +454,13 @@ UndoRedo::~UndoRedo() { clear_history(); } -void UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - if (p_argcount < 2) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 0; - return; - } - - if (p_args[0]->get_type() != Variant::OBJECT) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return; - } - - if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return; - } - - r_error.error = Callable::CallError::CALL_OK; - - Object *object = *p_args[0]; - StringName method = *p_args[1]; - - add_do_methodp(object, method, p_args + 2, p_argcount - 2); -} - -void UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - if (p_argcount < 2) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 0; - return; - } - - if (p_args[0]->get_type() != Variant::OBJECT) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return; - } - - if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return; - } - - r_error.error = Callable::CallError::CALL_OK; - - Object *object = *p_args[0]; - StringName method = *p_args[1]; - - add_undo_methodp(object, method, p_args + 2, p_argcount - 2); -} - void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE)); ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action); - { - MethodInfo mi; - mi.name = "add_do_method"; - mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); - mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &UndoRedo::_add_do_method, mi, varray(), false); - } - - { - MethodInfo mi; - mi.name = "add_undo_method"; - mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); - mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &UndoRedo::_add_undo_method, mi, varray(), false); - } - + ClassDB::bind_method(D_METHOD("add_do_method", "callable"), &UndoRedo::add_do_method); + ClassDB::bind_method(D_METHOD("add_undo_method", "callable"), &UndoRedo::add_undo_method); ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &UndoRedo::add_do_property); ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property); ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference); diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index 63cf3e5cbe..c7c58697c3 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -46,8 +46,6 @@ public: }; typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name); - void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount); typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value); @@ -58,14 +56,14 @@ private: TYPE_METHOD, TYPE_PROPERTY, TYPE_REFERENCE - }; + } type; - Type type; bool force_keep_in_merge_ends; Ref<RefCounted> ref; ObjectID object; StringName name; - Vector<Variant> args; + Callable callable; + Variant value; void delete_reference(); }; @@ -106,30 +104,8 @@ protected: public: void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE); - void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount); - void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount); - - template <typename... VarArgs> - void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { - Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. - const Variant *argptrs[sizeof...(p_args) + 1]; - for (uint32_t i = 0; i < sizeof...(p_args); i++) { - argptrs[i] = &args[i]; - } - - add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); - } - template <typename... VarArgs> - void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { - Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. - const Variant *argptrs[sizeof...(p_args) + 1]; - for (uint32_t i = 0; i < sizeof...(p_args); i++) { - argptrs[i] = &args[i]; - } - - add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); - } - + void add_do_method(const Callable &p_callable); + void add_undo_method(const Callable &p_callable); void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value); void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value); void add_do_reference(Object *p_object); diff --git a/core/os/os.h b/core/os/os.h index 363697ea30..0f79ff1a23 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -69,6 +69,7 @@ class OS { // so we can retrieve the rendering drivers available int _display_driver_id = -1; String _current_rendering_driver_name; + String _current_rendering_method; protected: void _set_logger(CompositeLogger *p_logger); @@ -98,6 +99,8 @@ protected: virtual void initialize_joypads() = 0; void set_current_rendering_driver_name(String p_driver_name) { _current_rendering_driver_name = p_driver_name; } + void set_current_rendering_method(String p_name) { _current_rendering_method = p_name; } + void set_display_driver_id(int p_display_driver_id) { _display_driver_id = p_display_driver_id; } virtual void set_main_loop(MainLoop *p_main_loop) = 0; @@ -116,6 +119,8 @@ public: static OS *get_singleton(); String get_current_rendering_driver_name() const { return _current_rendering_driver_name; } + String get_current_rendering_method() const { return _current_rendering_method; } + int get_display_driver_id() const { return _display_driver_id; } void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR); @@ -161,6 +166,8 @@ public: virtual bool set_environment(const String &p_var, const String &p_value) const = 0; virtual String get_name() const = 0; + virtual String get_distribution_name() const = 0; + virtual String get_version() const = 0; virtual List<String> get_cmdline_args() const { return _cmdline; } virtual List<String> get_cmdline_user_args() const { return _user_args; } virtual List<String> get_cmdline_platform_args() const { return List<String>(); } diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 6650d9be23..bad53ab4e6 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -58,6 +58,7 @@ #include "core/io/resource_format_binary.h" #include "core/io/resource_importer.h" #include "core/io/resource_uid.h" +#include "core/io/stream_peer_gzip.h" #include "core/io/stream_peer_tls.h" #include "core/io/tcp_server.h" #include "core/io/translation_loader_po.h" @@ -87,6 +88,8 @@ static Ref<TranslationLoaderPO> resource_format_po; static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto; static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto; static Ref<NativeExtensionResourceLoader> resource_loader_native_extension; +static Ref<ResourceFormatSaverJSON> resource_saver_json; +static Ref<ResourceFormatLoaderJSON> resource_loader_json; static core_bind::ResourceLoader *_resource_loader = nullptr; static core_bind::ResourceSaver *_resource_saver = nullptr; @@ -182,6 +185,7 @@ void register_core_types() { GDREGISTER_ABSTRACT_CLASS(StreamPeer); GDREGISTER_CLASS(StreamPeerExtension); GDREGISTER_CLASS(StreamPeerBuffer); + GDREGISTER_CLASS(StreamPeerGZIP); GDREGISTER_CLASS(StreamPeerTCP); GDREGISTER_CLASS(TCPServer); @@ -211,6 +215,12 @@ void register_core_types() { resource_format_loader_crypto.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_loader_crypto); + resource_loader_json.instantiate(); + ResourceLoader::add_resource_format_loader(resource_loader_json); + + resource_saver_json.instantiate(); + ResourceSaver::add_resource_format_saver(resource_saver_json); + GDREGISTER_CLASS(MainLoop); GDREGISTER_CLASS(Translation); GDREGISTER_CLASS(OptimizedTranslation); @@ -220,8 +230,8 @@ void register_core_types() { GDREGISTER_CLASS(ResourceFormatLoader); GDREGISTER_CLASS(ResourceFormatSaver); - GDREGISTER_CLASS(core_bind::File); - GDREGISTER_CLASS(core_bind::Directory); + GDREGISTER_ABSTRACT_CLASS(FileAccess); + GDREGISTER_ABSTRACT_CLASS(DirAccess); GDREGISTER_CLASS(core_bind::Thread); GDREGISTER_CLASS(core_bind::Mutex); GDREGISTER_CLASS(core_bind::Semaphore); @@ -241,6 +251,8 @@ void register_core_types() { GDREGISTER_CLASS(EncodedObjectAsID); GDREGISTER_CLASS(RandomNumberGenerator); + GDREGISTER_ABSTRACT_CLASS(ImageFormatLoader); + GDREGISTER_CLASS(ImageFormatLoaderExtension); GDREGISTER_ABSTRACT_CLASS(ResourceImporter); GDREGISTER_CLASS(NativeExtension); @@ -387,6 +399,12 @@ void unregister_core_types() { ResourceLoader::remove_resource_format_loader(resource_format_loader_crypto); resource_format_loader_crypto.unref(); + ResourceSaver::remove_resource_format_saver(resource_saver_json); + resource_saver_json.unref(); + + ResourceLoader::remove_resource_format_loader(resource_loader_json); + resource_loader_json.unref(); + if (ip) { memdelete(ip); } diff --git a/core/string/locales.h b/core/string/locales.h index 32d6608ec2..0ccb17a436 100644 --- a/core/string/locales.h +++ b/core/string/locales.h @@ -1072,6 +1072,7 @@ static const char *script_list[][2] = { { "Jurchen", "Jurc" }, { "Kayah Li", "Kali" }, { "Katakana", "Kana" }, + { "Kawi", "Kawi" }, { "Kharoshthi", "Khar" }, { "Khmer", "Khmr" }, { "Khojki", "Khoj" }, @@ -1110,6 +1111,7 @@ static const char *script_list[][2] = { { "Meitei Mayek", "Mtei" }, { "Multani", "Mult" }, { "Myanmar (Burmese)", "Mymr" }, + { "​Nag Mundari", "Nagm" }, { "Nandinagari", "Nand" }, { "Old North Arabian", "Narb" }, { "Nabataean", "Nbat" }, diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index b280fc9fe3..f24ffeb1a9 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3727,36 +3727,6 @@ String Variant::get_callable_error_text(const Callable &p_callable, const Varian return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, p_argcount, ce); } -String vformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) { - Array args; - if (p1.get_type() != Variant::NIL) { - args.push_back(p1); - - if (p2.get_type() != Variant::NIL) { - args.push_back(p2); - - if (p3.get_type() != Variant::NIL) { - args.push_back(p3); - - if (p4.get_type() != Variant::NIL) { - args.push_back(p4); - - if (p5.get_type() != Variant::NIL) { - args.push_back(p5); - } - } - } - } - } - - bool error = false; - String fmt = p_text.sprintf(args, &error); - - ERR_FAIL_COND_V_MSG(error, String(), fmt); - - return fmt; -} - void Variant::register_types() { _register_variant_operators(); _register_variant_methods(); diff --git a/core/variant/variant.h b/core/variant/variant.h index 212f94a9a8..b0738e7d44 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -552,9 +552,6 @@ public: void zero(); Variant duplicate(bool p_deep = false) const; Variant recursive_duplicate(bool p_deep, int recursion_count) const; - static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst); - static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst); - static void sub(const Variant &a, const Variant &b, Variant &r_dst); /* Built-In Methods */ @@ -807,7 +804,22 @@ const Variant::ObjData &Variant::_get_obj() const { return *reinterpret_cast<const ObjData *>(&_data._mem[0]); } -String vformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant()); +template <typename... VarArgs> +String vformat(const String &p_text, const VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + Array args_array; + args_array.resize(sizeof...(p_args)); + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + args_array[i] = args[i]; + } + + bool error = false; + String fmt = p_text.sprintf(args_array, &error); + + ERR_FAIL_COND_V_MSG(error, String(), fmt); + + return fmt; +} template <typename... VarArgs> Callable Callable::bind(VarArgs... p_args) { diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 57b953f7f0..ff67b187ef 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -1911,572 +1911,6 @@ Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const { } } -void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) { - if (a.type != b.type) { - return; - } - - switch (a.type) { - case NIL: { - r_dst = Variant(); - } - return; - case INT: { - int64_t va = a._data._int; - int64_t vb = b._data._int; - r_dst = int(va - vb); - } - return; - case FLOAT: { - double ra = a._data._float; - double rb = b._data._float; - r_dst = ra - rb; - } - return; - case VECTOR2: { - r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) - *reinterpret_cast<const Vector2 *>(b._data._mem); - } - return; - case VECTOR2I: { - int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x; - int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x; - int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y; - int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y; - r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby)); - } - return; - case RECT2: { - const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem); - const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem); - r_dst = Rect2(ra->position - rb->position, ra->size - rb->size); - } - return; - case RECT2I: { - const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem); - const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem); - - int32_t vax = ra->position.x; - int32_t vay = ra->position.y; - int32_t vbx = ra->size.x; - int32_t vby = ra->size.y; - int32_t vcx = rb->position.x; - int32_t vcy = rb->position.y; - int32_t vdx = rb->size.x; - int32_t vdy = rb->size.y; - - r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy)); - } - return; - case VECTOR3: { - r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) - *reinterpret_cast<const Vector3 *>(b._data._mem); - } - return; - case VECTOR3I: { - int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x; - int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x; - int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y; - int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y; - int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z; - int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z; - r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz)); - } - return; - case AABB: { - const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem); - const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem); - r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size); - } - return; - case QUATERNION: { - Quaternion empty_rot; - const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem); - const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem); - r_dst = (*qb).inverse() * *qa; - } - return; - case COLOR: { - const Color *ca = reinterpret_cast<const Color *>(a._data._mem); - const Color *cb = reinterpret_cast<const Color *>(b._data._mem); - float new_r = ca->r - cb->r; - float new_g = ca->g - cb->g; - float new_b = ca->b - cb->b; - float new_a = ca->a - cb->a; - new_r = new_r > 1.0 ? 1.0 : new_r; - new_g = new_g > 1.0 ? 1.0 : new_g; - new_b = new_b > 1.0 ? 1.0 : new_b; - new_a = new_a > 1.0 ? 1.0 : new_a; - r_dst = Color(new_r, new_g, new_b, new_a); - } - return; - default: { - r_dst = a; - } - return; - } -} - -void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) { - if (a.type != b.type) { - if (a.is_num() && b.is_num()) { - real_t va = a; - real_t vb = b; - r_dst = va + vb * c; - } else { - r_dst = a; - } - return; - } - - switch (a.type) { - case NIL: { - r_dst = Variant(); - } - return; - case INT: { - int64_t va = a._data._int; - int64_t vb = b._data._int; - r_dst = int(va + vb * c + 0.5); - } - return; - case FLOAT: { - double ra = a._data._float; - double rb = b._data._float; - r_dst = ra + rb * c; - } - return; - case VECTOR2: { - r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c; - } - return; - case VECTOR2I: { - int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x; - int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x; - int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y; - int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y; - r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5)); - } - return; - case RECT2: { - const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem); - const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem); - r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c); - } - return; - case RECT2I: { - const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem); - const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem); - - int32_t vax = ra->position.x; - int32_t vay = ra->position.y; - int32_t vbx = ra->size.x; - int32_t vby = ra->size.y; - int32_t vcx = rb->position.x; - int32_t vcy = rb->position.y; - int32_t vdx = rb->size.x; - int32_t vdy = rb->size.y; - - r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5)); - } - return; - case VECTOR3: { - r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c; - } - return; - case VECTOR3I: { - int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x; - int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x; - int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y; - int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y; - int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z; - int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z; - r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5)); - } - return; - case AABB: { - const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem); - const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem); - r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c); - } - return; - case QUATERNION: { - Quaternion empty_rot; - const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem); - const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem); - r_dst = *qa * empty_rot.slerp(*qb, c); - } - return; - case COLOR: { - const Color *ca = reinterpret_cast<const Color *>(a._data._mem); - const Color *cb = reinterpret_cast<const Color *>(b._data._mem); - float new_r = ca->r + cb->r * c; - float new_g = ca->g + cb->g * c; - float new_b = ca->b + cb->b * c; - float new_a = ca->a + cb->a * c; - new_r = new_r > 1.0 ? 1.0 : new_r; - new_g = new_g > 1.0 ? 1.0 : new_g; - new_b = new_b > 1.0 ? 1.0 : new_b; - new_a = new_a > 1.0 ? 1.0 : new_a; - r_dst = Color(new_r, new_g, new_b, new_a); - } - return; - default: { - r_dst = c < 0.5 ? a : b; - } - return; - } -} - -void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) { - if (a.type != b.type) { - if (a.is_num() && b.is_num()) { - //not as efficient but.. - real_t va = a; - real_t vb = b; - r_dst = va + (vb - va) * c; - - } else { - r_dst = a; - } - return; - } - - switch (a.type) { - case NIL: { - r_dst = Variant(); - } - return; - case BOOL: { - r_dst = a; - } - return; - case INT: { - int64_t va = a._data._int; - int64_t vb = b._data._int; - r_dst = int(va + (vb - va) * c); - } - return; - case FLOAT: { - real_t va = a._data._float; - real_t vb = b._data._float; - r_dst = va + (vb - va) * c; - } - return; - case STRING: { - //this is pretty funny and bizarre, but artists like to use it for typewriter effects - String sa = *reinterpret_cast<const String *>(a._data._mem); - String sb = *reinterpret_cast<const String *>(b._data._mem); - String dst; - int sa_len = sa.length(); - int sb_len = sb.length(); - int csize = sa_len + (sb_len - sa_len) * c; - if (csize == 0) { - r_dst = ""; - return; - } - dst.resize(csize + 1); - dst[csize] = 0; - int split = csize / 2; - - for (int i = 0; i < csize; i++) { - char32_t chr = ' '; - - if (i < split) { - if (i < sa.length()) { - chr = sa[i]; - } else if (i < sb.length()) { - chr = sb[i]; - } - - } else { - if (i < sb.length()) { - chr = sb[i]; - } else if (i < sa.length()) { - chr = sa[i]; - } - } - - dst[i] = chr; - } - - r_dst = dst; - } - return; - case VECTOR2: { - r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c); - } - return; - case VECTOR2I: { - int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x; - int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x; - int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y; - int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y; - r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5)); - } - return; - - case RECT2: { - r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c)); - } - return; - case RECT2I: { - const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem); - const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem); - - int32_t vax = ra->position.x; - int32_t vay = ra->position.y; - int32_t vbx = ra->size.x; - int32_t vby = ra->size.y; - int32_t vcx = rb->position.x; - int32_t vcy = rb->position.y; - int32_t vdx = rb->size.x; - int32_t vdy = rb->size.y; - - r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5)); - } - return; - - case VECTOR3: { - r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c); - } - return; - case VECTOR3I: { - int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x; - int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x; - int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y; - int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y; - int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z; - int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z; - r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5)); - } - return; - - case TRANSFORM2D: { - r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c); - } - return; - case PLANE: { - r_dst = a; - } - return; - case QUATERNION: { - r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c); - } - return; - case AABB: { - r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c)); - } - return; - case BASIS: { - r_dst = a._data._basis->lerp(*b._data._basis, c); - } - return; - case TRANSFORM3D: { - r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c); - } - return; - case COLOR: { - r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c); - } - return; - case STRING_NAME: { - r_dst = a; - } - return; - case NODE_PATH: { - r_dst = a; - } - return; - case RID: { - r_dst = a; - } - return; - case OBJECT: { - r_dst = a; - } - return; - case DICTIONARY: { - } - return; - case ARRAY: { - r_dst = a; - } - return; - case PACKED_BYTE_ARRAY: { - r_dst = a; - } - return; - case PACKED_INT32_ARRAY: { - const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array); - const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array); - int32_t sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<int32_t> v; - v.resize(sz); - { - int32_t *vw = v.ptrw(); - const int32_t *ar = arr_a->ptr(); - const int32_t *br = arr_b->ptr(); - - Variant va; - for (int32_t i = 0; i < sz; i++) { - Variant::interpolate(ar[i], br[i], c, va); - vw[i] = va; - } - } - r_dst = v; - } - } - return; - case PACKED_INT64_ARRAY: { - const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array); - const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array); - int64_t sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<int64_t> v; - v.resize(sz); - { - int64_t *vw = v.ptrw(); - const int64_t *ar = arr_a->ptr(); - const int64_t *br = arr_b->ptr(); - - Variant va; - for (int64_t i = 0; i < sz; i++) { - Variant::interpolate(ar[i], br[i], c, va); - vw[i] = va; - } - } - r_dst = v; - } - } - return; - case PACKED_FLOAT32_ARRAY: { - const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array); - const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array); - int sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<float> v; - v.resize(sz); - { - float *vw = v.ptrw(); - const float *ar = arr_a->ptr(); - const float *br = arr_b->ptr(); - - Variant va; - for (int i = 0; i < sz; i++) { - Variant::interpolate(ar[i], br[i], c, va); - vw[i] = va; - } - } - r_dst = v; - } - } - return; - case PACKED_FLOAT64_ARRAY: { - const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array); - const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array); - int sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<double> v; - v.resize(sz); - { - double *vw = v.ptrw(); - const double *ar = arr_a->ptr(); - const double *br = arr_b->ptr(); - - Variant va; - for (int i = 0; i < sz; i++) { - Variant::interpolate(ar[i], br[i], c, va); - vw[i] = va; - } - } - r_dst = v; - } - } - return; - case PACKED_STRING_ARRAY: { - r_dst = a; - } - return; - case PACKED_VECTOR2_ARRAY: { - const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array); - const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array); - int sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<Vector2> v; - v.resize(sz); - { - Vector2 *vw = v.ptrw(); - const Vector2 *ar = arr_a->ptr(); - const Vector2 *br = arr_b->ptr(); - - for (int i = 0; i < sz; i++) { - vw[i] = ar[i].lerp(br[i], c); - } - } - r_dst = v; - } - } - return; - case PACKED_VECTOR3_ARRAY: { - const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array); - const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array); - int sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<Vector3> v; - v.resize(sz); - { - Vector3 *vw = v.ptrw(); - const Vector3 *ar = arr_a->ptr(); - const Vector3 *br = arr_b->ptr(); - - for (int i = 0; i < sz; i++) { - vw[i] = ar[i].lerp(br[i], c); - } - } - r_dst = v; - } - } - return; - case PACKED_COLOR_ARRAY: { - const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array); - const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array); - int sz = arr_a->size(); - if (sz == 0 || arr_b->size() != sz) { - r_dst = a; - } else { - Vector<Color> v; - v.resize(sz); - { - Color *vw = v.ptrw(); - const Color *ar = arr_a->ptr(); - const Color *br = arr_b->ptr(); - - for (int i = 0; i < sz; i++) { - vw[i] = ar[i].lerp(br[i], c); - } - } - r_dst = v; - } - } - return; - default: { - r_dst = a; - } - } -} - void Variant::_register_variant_setters_getters() { register_named_setters_getters(); register_indexed_setters_getters(); diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml index 69cd54a79b..7f582e4be7 100644 --- a/doc/classes/AESContext.xml +++ b/doc/classes/AESContext.xml @@ -45,6 +45,7 @@ public class Example : Node { public AESContext Aes = new AESContext(); + public override void _Ready() { string key = "My secret key!!!"; // Key must be either 16 or 32 bytes. diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml index 19cd9d21d7..331862ebfa 100644 --- a/doc/classes/AStarGrid2D.xml +++ b/doc/classes/AStarGrid2D.xml @@ -6,14 +6,24 @@ <description> Compared to [AStar2D] you don't need to manually create points or connect them together. It also supports multiple type of heuristics and modes for diagonal movement. This class also provides a jumping mode which is faster to calculate than without it in the [AStar2D] class. In contrast to [AStar2D], you only need set the [member size] of the grid, optionally set the [member cell_size] and then call the [method update] method: - [codeblock] + [codeblocks] + [gdscript] var astar_grid = AStarGrid2D.new() astar_grid.size = Vector2i(32, 32) astar_grid.cell_size = Vector2(16, 16) astar_grid.update() print(astar_grid.get_id_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4) print(astar_grid.get_point_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64) - [/codeblock] + [/gdscript] + [csharp] + AStarGrid2D astarGrid = new AStarGrid2D(); + astarGrid.Size = new Vector2i(32, 32); + astarGrid.CellSize = new Vector2i(16, 16); + astarGrid.Update(); + GD.Print(astarGrid.GetIdPath(Vector2i.Zero, new Vector2i(3, 4))); // prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4) + GD.Print(astarGrid.GetPointPath(Vector2i.Zero, new Vector2i(3, 4))); // prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64) + [/csharp] + [/codeblocks] </description> <tutorials> </tutorials> diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml index b207eda27f..afbe34816a 100644 --- a/doc/classes/AnimatedSprite2D.xml +++ b/doc/classes/AnimatedSprite2D.xml @@ -5,6 +5,8 @@ </brief_description> <description> [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, call [method stop] or 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> @@ -17,13 +19,14 @@ <param index="0" name="anim" type="StringName" default="&""" /> <param index="1" name="backwards" type="bool" default="false" /> <description> - Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse. + Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation is played in reverse. </description> </method> <method name="stop"> <return type="void" /> <description> - Stops the current animation (does not reset the frame counter). + Stops the current [member animation] at the current [member frame]. + [b]Note:[/b] This method resets the current frame's elapsed time. If this behavior is undesired, consider setting [member speed_scale] to [code]0[/code], instead. </description> </method> </methods> @@ -50,10 +53,10 @@ The texture's drawing offset. </member> <member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false"> - If [code]true[/code], the [member animation] is currently playing. + If [code]true[/code], the [member animation] is currently playing. Setting this property to [code]false[/code] is the equivalent of calling [method stop]. </member> <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0"> - The animation speed is multiplied by this value. + The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse. If set to [code]0[/code], the animation is paused, preserving the current frame's elapsed time. </member> </members> <signals> diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml index 58d3ca6ad3..09baf882fb 100644 --- a/doc/classes/AnimatedSprite3D.xml +++ b/doc/classes/AnimatedSprite3D.xml @@ -4,7 +4,9 @@ 2D sprite node in 3D world, that can use multiple 2D textures for animation. </brief_description> <description> - Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel. + [AnimatedSprite3D] is similar to the [Sprite3D] node, except it carries multiple textures as animation [member 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, call [method stop] or set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time. </description> <tutorials> <link title="2D Sprite animation (also applies to 3D)">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link> @@ -15,13 +17,14 @@ <param index="0" name="anim" type="StringName" default="&""" /> <param index="1" name="backwards" type="bool" default="false" /> <description> - Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation will be played in reverse. + Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation is played in reverse. </description> </method> <method name="stop"> <return type="void" /> <description> - Stops the current animation (does not reset the frame counter). + Stops the current [member animation] at the current [member frame]. + [b]Note:[/b] This method resets the current frame's elapsed time. If this behavior is undesired, consider setting [member speed_scale] to [code]0[/code], instead. </description> </method> </methods> @@ -36,10 +39,10 @@ The [SpriteFrames] resource containing the animation(s). </member> <member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false"> - If [code]true[/code], the [member animation] is currently playing. + If [code]true[/code], the [member animation] is currently playing. Setting this property to [code]false[/code] is the equivalent of calling [method stop]. </member> <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0"> - The animation speed is multiplied by this value. + The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse. If set to [code]0[/code], the animation is paused, preserving the current frame's elapsed time. </member> </members> <signals> diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml index 4c7943ece3..2a765ac8d6 100644 --- a/doc/classes/AnimationNodeBlendTree.xml +++ b/doc/classes/AnimationNodeBlendTree.xml @@ -87,6 +87,14 @@ The global offset of all sub-nodes. </member> </members> + <signals> + <signal name="node_changed"> + <param index="0" name="node_name" type="StringName" /> + <description> + Emitted when the input port information is changed. + </description> + </signal> + </signals> <constants> <constant name="CONNECTION_OK" value="0"> The connection was successful. diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 710dc55a4b..d24703203b 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -268,6 +268,11 @@ [b]Note:[/b] This signal is not emitted if an animation is looping. </description> </signal> + <signal name="animation_list_changed"> + <description> + Notifies when an animation list is changed. + </description> + </signal> <signal name="animation_started"> <param index="0" name="anim_name" type="StringName" /> <description> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index f2bf74f495..27797b00b5 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -54,6 +54,13 @@ The root animation node of this [AnimationTree]. See [AnimationNode]. </member> </members> + <signals> + <signal name="animation_player_changed"> + <description> + Emitted when the [member anim_player] is changed. + </description> + </signal> + </signals> <constants> <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback"> The animations will progress during the physics frame (i.e. [method Node._physics_process]). diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index ee28675d89..cbb58a3e1e 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -28,7 +28,7 @@ <return type="Texture2D" /> <param index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" /> <description> - Returns the [Texture] associated with the specified [enum TextureParam]. + Returns the [Texture2D] associated with the specified [enum TextureParam]. </description> </method> <method name="set_feature"> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 70d825efac..d74f49c897 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -310,16 +310,16 @@ # If using this method in a script that redraws constantly, move the # `default_font` declaration to a member variable assigned in `_ready()` # so the Control is only created once. - var default_font = Control.new().get_font("font") - var default_font_size = Control.new().get_font_size("font_size") - draw_string(default_font, Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size) + var default_font = ThemeDB.fallback_font + var default_font_size = ThemeDB.fallback_font_size + draw_string(default_font, Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, default_font_size) [/gdscript] [csharp] // If using this method in a script that redraws constantly, move the - // `default_font` declaration to a member variable assigned in `_ready()` + // `default_font` declaration to a member variable assigned in `_Ready()` // so the Control is only created once. - Font defaultFont = new Control().GetFont("font"); - int defaultFontSize = new Control().GetFontSize("font_size"); + Font defaultFont = ThemeDB.FallbackFont; + int defaultFontSize = ThemeDB.FallbackFontSize; DrawString(defaultFont, new Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, defaultFontSize); [/csharp] [/codeblocks] diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml index 7173388027..0cdebeda95 100644 --- a/doc/classes/Cubemap.xml +++ b/doc/classes/Cubemap.xml @@ -4,9 +4,9 @@ 6-sided texture typically used in 3D rendering. </brief_description> <description> - A cubemap is a 6-sided texture typically used for faking reflections in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods. + A cubemap is made of 6 textures organized in layers. They are typically used for faking reflections (see [ReflectionProbe]) in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods. This resource is typically used as a uniform in custom shaders. Few core Godot methods make use of Cubemap resources. - [b]Note:[/b] Godot doesn't support using cubemaps as a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map. + [b]Note:[/b] Godot doesn't support using cubemaps in a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map. </description> <tutorials> </tutorials> diff --git a/doc/classes/CubemapArray.xml b/doc/classes/CubemapArray.xml index 4fca842b5a..7f001155e4 100644 --- a/doc/classes/CubemapArray.xml +++ b/doc/classes/CubemapArray.xml @@ -1,8 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CubemapArray" inherits="ImageTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + A single composite texture resource which consists of multiple [Cubemap]s. </brief_description> <description> + [CubemapArray]s are made of an array of [Cubemap]s. Accordingly, like [Cubemap]s they are made of multiple textures the amount of which must be divisible by 6 (one image for each face of the cube). The primary benefit of [CubemapArray]s is that they can be accessed in shader code using a single texture reference. In other words, you can pass multiple [Cubemap]s into a shader using a single [CubemapArray]. + Generally, [CubemapArray]s provide a more efficent way for storing multiple [Cubemap]s, than storing multiple [Cubemap]s themselves in an array. + Internally Godot, uses [CubemapArray]s for many effects including the [Sky], if you set [member ProjectSettings.rendering/reflections/sky_reflections/texture_array_reflections] to [code]true[/code]. + [b]Note:[/b] [CubemapArray] is not supported in the OpenGL 3 rendering backend. </description> <tutorials> </tutorials> diff --git a/doc/classes/Directory.xml b/doc/classes/DirAccess.xml index c9a9f346a5..cb7bf56f11 100644 --- a/doc/classes/Directory.xml +++ b/doc/classes/DirAccess.xml @@ -1,18 +1,27 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Directory" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="DirAccess" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Type used to handle the filesystem. </brief_description> <description> Directory type. It is used to manage directories and their content (not restricted to the project folder). - When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code]. + [DirAccess] can't be instantiated directly. Instead it is created with a static method that takes a path for which it will be opened. + Most of the methods have a static alternative that can be used without creating a [DirAccess]. Static methods only support absolute paths (including [code]res://[/code] and [code]user://[/code]). + [codeblock] + # Standard + var dir = Directory.new() + dir.open("user://levels") + dir.make_dir("world1") + # Static + Directory.make_dir_absolute("user://levels/world1") + [/codeblock] [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources. Here is an example on how to iterate through the files of a directory: [codeblocks] [gdscript] func dir_contents(path): - var dir = Directory.new() - if dir.open(path) == OK: + var dir = DirAccess.open(path) + if dir: dir.list_dir_begin() var file_name = dir.get_next() while file_name != "": @@ -27,8 +36,8 @@ [csharp] public void DirContents(string path) { - var dir = new Directory(); - if (dir.Open(path) == Error.Ok) + using var dir = DirAccess.Open(path); + if (dir != null) { dir.ListDirBegin(); string fileName = dir.GetNext(); @@ -59,7 +68,7 @@ <methods> <method name="change_dir"> <return type="int" enum="Error" /> - <param index="0" name="todir" type="String" /> + <param index="0" name="to_dir" type="String" /> <description> Changes the currently opened directory to the one passed as an argument. The argument can be relative to the current directory (e.g. [code]newdir[/code] or [code]../newdir[/code]), or an absolute path (e.g. [code]/tmp/newdir[/code] or [code]res://somedir/newdir[/code]). Returns one of the [enum Error] code constants ([code]OK[/code] on success). @@ -69,11 +78,22 @@ <return type="int" enum="Error" /> <param index="0" name="from" type="String" /> <param index="1" name="to" type="String" /> + <param index="2" name="chmod_flags" type="int" default="-1" /> <description> Copies the [param from] file to the [param to] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten. + If [param chmod_flags] is different than [code]-1[/code], the unix permissions for the destination path will be set to the provided value, if available on the current operating system. Returns one of the [enum Error] code constants ([code]OK[/code] on success). </description> </method> + <method name="copy_absolute" qualifiers="static"> + <return type="int" enum="Error" /> + <param index="0" name="from" type="String" /> + <param index="1" name="to" type="String" /> + <param index="2" name="chmod_flags" type="int" default="-1" /> + <description> + Static version of [method copy]. Supports only absolute paths. + </description> + </method> <method name="current_is_dir" qualifiers="const"> <return type="bool" /> <description> @@ -85,7 +105,13 @@ <param index="0" name="path" type="String" /> <description> Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path. - If the [Directory] is not open, the path is relative to [code]res://[/code]. + </description> + </method> + <method name="dir_exists_absolute" qualifiers="static"> + <return type="bool" /> + <param index="0" name="path" type="String" /> + <description> + Static version of [method dir_exists]. Supports only absolute paths. </description> </method> <method name="file_exists"> @@ -93,11 +119,12 @@ <param index="0" name="path" type="String" /> <description> Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path. - If the [Directory] is not open, the path is relative to [code]res://[/code]. + For a static equivalent, use [method FileAccess.file_exists]. </description> </method> - <method name="get_current_dir"> + <method name="get_current_dir" qualifiers="const"> <return type="String" /> + <param index="0" name="include_drive" type="bool" default="true" /> <description> Returns the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]). </description> @@ -105,7 +132,7 @@ <method name="get_current_drive"> <return type="int" /> <description> - Returns the currently opened directory's drive index. See [method get_drive] to convert returned index to the name of the drive. + Returns the currently opened directory's drive index. See [method get_drive_name] to convert returned index to the name of the drive. </description> </method> <method name="get_directories"> @@ -115,17 +142,15 @@ Affected by [member include_hidden] and [member include_navigational]. </description> </method> - <method name="get_drive"> - <return type="String" /> - <param index="0" name="idx" type="int" /> + <method name="get_directories_at" qualifiers="static"> + <return type="PackedStringArray" /> + <param index="0" name="path" type="String" /> <description> - On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). - On macOS, returns the path to the mounted volume passed as an argument. - On Linux, returns the path to the mounted volume or GTK 3 bookmark passed as an argument. - On other platforms, or if the requested drive does not exist, the method returns an empty String. + Returns a [PackedStringArray] containing filenames of the directory contents, excluding files, at the given [param path]. The array is sorted alphabetically. + Use [method get_directories] if you want more control of what gets included. </description> </method> - <method name="get_drive_count"> + <method name="get_drive_count" qualifiers="static"> <return type="int" /> <description> On Windows, returns the number of drives (partitions) mounted on the current filesystem. @@ -134,6 +159,16 @@ On other platforms, the method returns 0. </description> </method> + <method name="get_drive_name" qualifiers="static"> + <return type="String" /> + <param index="0" name="idx" type="int" /> + <description> + On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). + On macOS, returns the path to the mounted volume passed as an argument. + On Linux, returns the path to the mounted volume or GTK 3 bookmark passed as an argument. + On other platforms, or if the requested drive does not exist, the method returns an empty String. + </description> + </method> <method name="get_files"> <return type="PackedStringArray" /> <description> @@ -141,11 +176,25 @@ Affected by [member include_hidden]. </description> </method> + <method name="get_files_at" qualifiers="static"> + <return type="PackedStringArray" /> + <param index="0" name="path" type="String" /> + <description> + Returns a [PackedStringArray] containing filenames of the directory contents, excluding directories, at the given [param path]. The array is sorted alphabetically. + Use [method get_files] if you want more control of what gets included. + </description> + </method> <method name="get_next"> <return type="String" /> <description> - Returns the next element (file or directory) in the current directory (including [code].[/code] and [code]..[/code], unless [code]skip_navigational[/code] was given to [method list_dir_begin]). - The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty String and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case). + Returns the next element (file or directory) in the current directory. + The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty [String] and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case). + </description> + </method> + <method name="get_open_error" qualifiers="static"> + <return type="int" enum="Error" /> + <description> + Returns the result of the last [method open] call in the current thread. </description> </method> <method name="get_space_left"> @@ -176,6 +225,13 @@ Returns one of the [enum Error] code constants ([code]OK[/code] on success). </description> </method> + <method name="make_dir_absolute" qualifiers="static"> + <return type="int" enum="Error" /> + <param index="0" name="path" type="String" /> + <description> + Static version of [method make_dir]. Supports only absolute paths. + </description> + </method> <method name="make_dir_recursive"> <return type="int" enum="Error" /> <param index="0" name="path" type="String" /> @@ -184,12 +240,19 @@ Returns one of the [enum Error] code constants ([code]OK[/code] on success). </description> </method> - <method name="open"> + <method name="make_dir_recursive_absolute" qualifiers="static"> <return type="int" enum="Error" /> <param index="0" name="path" type="String" /> <description> - Opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]). - Returns one of the [enum Error] code constants ([code]OK[/code] on success). + Static version of [method make_dir_recursive]. Supports only absolute paths. + </description> + </method> + <method name="open" qualifiers="static"> + <return type="DirAccess" /> + <param index="0" name="path" type="String" /> + <description> + Creates a new [DirAccess] object and opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]). + Returns [code]null[/code] if opening the directory failed. You can use [method get_open_error] to check the error that ocurred. </description> </method> <method name="remove"> @@ -201,6 +264,13 @@ Returns one of the [enum Error] code constants ([code]OK[/code] on success). </description> </method> + <method name="remove_absolute" qualifiers="static"> + <return type="int" enum="Error" /> + <param index="0" name="path" type="String" /> + <description> + Static version of [method remove]. Supports only absolute paths. + </description> + </method> <method name="rename"> <return type="int" enum="Error" /> <param index="0" name="from" type="String" /> @@ -210,13 +280,21 @@ Returns one of the [enum Error] code constants ([code]OK[/code] on success). </description> </method> + <method name="rename_absolute" qualifiers="static"> + <return type="int" enum="Error" /> + <param index="0" name="from" type="String" /> + <param index="1" name="to" type="String" /> + <description> + Static version of [method rename]. Supports only absolute paths. + </description> + </method> </methods> <members> - <member name="include_hidden" type="bool" setter="set_include_hidden" getter="get_include_hidden" default="false"> + <member name="include_hidden" type="bool" setter="set_include_hidden" getter="get_include_hidden"> If [code]true[/code], hidden files are included when the navigating directory. Affects [method list_dir_begin], [method get_directories] and [method get_files]. </member> - <member name="include_navigational" type="bool" setter="set_include_navigational" getter="get_include_navigational" default="false"> + <member name="include_navigational" type="bool" setter="set_include_navigational" getter="get_include_navigational"> If [code]true[/code], [code].[/code] and [code]..[/code] are included when navigating the directory. Affects [method list_dir_begin] and [method get_directories]. </member> diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index d22d64c276..a1dee7ecc7 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1336,6 +1336,15 @@ Depending on the platform and used renderer, the engine will fall back to [constant VSYNC_ENABLED], if the desired mode is not supported. </description> </method> + <method name="window_set_window_buttons_offset"> + <return type="void" /> + <param index="0" name="offset" type="Vector2i" /> + <param index="1" name="window_id" type="int" default="0" /> + <description> + When [constant WINDOW_FLAG_EXTEND_TO_TITLE] flag is set, set offset to the center of the first titlebar button. + [b]Note:[/b] This flag is implemented on macOS. + </description> + </method> <method name="window_set_window_event_callback"> <return type="void" /> <param index="0" name="callback" type="Callable" /> diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml index 280a7bf34a..a1a43dd5bf 100644 --- a/doc/classes/EditorInspector.xml +++ b/doc/classes/EditorInspector.xml @@ -13,6 +13,14 @@ </description> <tutorials> </tutorials> + <methods> + <method name="get_selected_path" qualifiers="const"> + <return type="String" /> + <description> + Gets the path of the currently selected property. + </description> + </method> + </methods> <members> <member name="horizontal_scroll_mode" type="int" setter="set_horizontal_scroll_mode" getter="get_horizontal_scroll_mode" overrides="ScrollContainer" enum="ScrollContainer.ScrollMode" default="0" /> </members> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 8f4c848041..27cf410c15 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -237,7 +237,7 @@ # You can use a custom icon: return preload("res://addons/my_plugin/my_plugin_icon.svg") # Or use a built-in icon: - return get_editor_interface().get_base_control().get_icon("Node", "EditorIcons") + return get_editor_interface().get_base_control().get_theme_icon("Node", "EditorIcons") [/gdscript] [csharp] public override Texture2D GetPluginIcon() @@ -245,7 +245,7 @@ // You can use a custom icon: return ResourceLoader.Load<Texture2D>("res://addons/my_plugin/my_plugin_icon.svg"); // Or use a built-in icon: - return GetEditorInterface().GetBaseControl().GetIcon("Node", "EditorIcons"); + return GetEditorInterface().GetBaseControl().GetThemeIcon("Node", "EditorIcons"); } [/csharp] [/codeblocks] diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 7bac4bf7ac..9170c449bf 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -9,6 +9,13 @@ <tutorials> </tutorials> <methods> + <method name="_set_read_only" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="read_only" type="bool" /> + <description> + Called when the read-only status of the property is changed. It may be used to change custom controls into a read-only or modifiable state. + </description> + </method> <method name="_update_property" qualifiers="virtual"> <return type="void" /> <description> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 329cd3fe63..6007128965 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -405,7 +405,7 @@ If [code]true[/code], allows panning by holding down [kbd]Space[/kbd] in the 2D editor viewport (in addition to panning with the middle or right mouse buttons). If [code]false[/code], the left mouse button must be held down while holding down [kbd]Space[/kbd] to pan in the 2D editor viewport. </member> <member name="editors/panning/sub_editors_panning_scheme" type="int" setter="" getter=""> - Controls whether the mouse wheel scroll zooms or pans in subeditors. The list of affected subeditors is: animation blend tree editor, [Polygon2D] editor, tileset editor, texture region editor, visual shader editor and visual script editor. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/animation_editors_panning_scheme]. + Controls whether the mouse wheel scroll zooms or pans in subeditors. The list of affected subeditors is: animation blend tree editor, [Polygon2D] editor, tileset editor, texture region editor and visual shader editor. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/animation_editors_panning_scheme]. </member> <member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter=""> If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning then mouse the mouse back constantly. @@ -424,10 +424,10 @@ [b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code]. </member> <member name="editors/visual_editors/lines_curvature" type="float" setter="" getter=""> - The curvature to use for connection lines in the visual script and visual shader editors. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines. + The curvature to use for connection lines in the visual shader editor. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines. </member> <member name="editors/visual_editors/minimap_opacity" type="float" setter="" getter=""> - The opacity of the minimap displayed in the bottom-right corner of the visual script and visual shader editors. + The opacity of the minimap displayed in the bottom-right corner of the visual shader editor. </member> <member name="editors/visual_editors/visual_shader/port_preview_size" type="int" setter="" getter=""> 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. diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml index d028996db8..08986781cd 100644 --- a/doc/classes/EditorTranslationParserPlugin.xml +++ b/doc/classes/EditorTranslationParserPlugin.xml @@ -72,7 +72,7 @@ msgidsContextPlural.Add(new Godot.Collections.Array{"Only with context", "a friendly context", ""}); [/csharp] [/codeblocks] - [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [File] type. + [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [FileAccess] type. For example: [codeblocks] [gdscript] diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 301a3e55fb..ecf3d87a70 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -14,12 +14,20 @@ <description> Returns the name of the CPU architecture the Godot binary was built for. Possible return values are [code]x86_64[/code], [code]x86_32[/code], [code]arm64[/code], [code]armv7[/code], [code]rv64[/code], [code]riscv[/code], [code]ppc64[/code], [code]ppc[/code], [code]wasm64[/code] and [code]wasm32[/code]. To detect whether the current CPU architecture is 64-bit, you can use the fact that all 64-bit architecture names have [code]64[/code] in their name: - [codeblock] + [codeblocks] + [gdscript] if "64" in Engine.get_architecture_name(): print("Running on 64-bit CPU.") else: print("Running on 32-bit CPU.") - [/codeblock] + [/gdscript] + [csharp] + if (Engine.GetArchitectureName().Contains("64")) + GD.Print("Running on 64-bit CPU."); + else + GD.Print("Running on 32-bit CPU."); + [/csharp] + [/codeblocks] [b]Note:[/b] [method get_architecture_name] does [i]not[/i] return the name of the host CPU architecture. For example, if running an x86_32 Godot binary on a x86_64 system, the returned value will be [code]x86_32[/code]. </description> </method> @@ -83,11 +91,24 @@ <description> Returns the total number of frames passed since engine initialization which is advanced on each [b]physics frame[/b]. See also [method get_process_frames]. [method get_physics_frames] can be used to run expensive logic less often without relying on a [Timer]: - [codeblock] + [codeblocks] + [gdscript] func _physics_process(_delta): if Engine.get_physics_frames() % 2 == 0: pass # Run expensive logic only once every 2 physics frames here. - [/codeblock] + [/gdscript] + [csharp] + public override void _PhysicsProcess(double delta) + { + base._PhysicsProcess(delta); + + if (Engine.GetPhysicsFrames() % 2 == 0) + { + // Run expensive logic only once every 2 physics frames here. + } + } + [/csharp] + [/codeblocks] </description> </method> <method name="get_physics_interpolation_fraction" qualifiers="const"> @@ -101,11 +122,24 @@ <description> Returns the total number of frames passed since engine initialization which is advanced on each [b]process frame[/b], regardless of whether the render loop is enabled. See also [method get_frames_drawn] and [method get_physics_frames]. [method get_process_frames] can be used to run expensive logic less often without relying on a [Timer]: - [codeblock] + [codeblocks] + [gdscript] func _process(_delta): if Engine.get_process_frames() % 2 == 0: pass # Run expensive logic only once every 2 process (render) frames here. - [/codeblock] + [/gdscript] + [csharp] + public override void _Process(double delta) + { + base._Process(delta); + + if (Engine.GetProcessFrames() % 2 == 0) + { + // Run expensive logic only once every 2 physics frames here. + } + } + [/csharp] + [/codeblocks] </description> </method> <method name="get_script_language" qualifiers="const"> @@ -182,12 +216,20 @@ <return type="bool" /> <description> Returns [code]true[/code] if the script is currently running inside the editor, [code]false[/code] otherwise. This is useful for [code]@tool[/code] scripts to conditionally draw editor helpers, or prevent accidentally running "game" code that would affect the scene state while in the editor: - [codeblock] + [codeblocks] + [gdscript] if Engine.is_editor_hint(): draw_gizmos() else: simulate_physics() - [/codeblock] + [/gdscript] + [csharp] + if (Engine.IsEditorHint()) + DrawGizmos(); + else + SimulatePhysics(); + [/csharp] + [/codeblocks] See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information. [b]Note:[/b] To detect whether the script is run from an editor [i]build[/i] (e.g. when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] will evaluate to [code]true[/code] both when the code is running in the editor and when running the project from the editor, but it will evaluate to [code]false[/code] when the code is run from an exported project. </description> diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index 695f2cbc66..243a28e73d 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -86,7 +86,7 @@ This is useful to simulate [url=https://en.wikipedia.org/wiki/Aerial_perspective]aerial perspective[/url] in large scenes with low density fog. However, it is not very useful for high-density fog, as the sky will shine through. When set to [code]1.0[/code], the fog color comes completely from the [Sky]. If set to [code]0.0[/code], aerial perspective is disabled. </member> <member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.01"> - The exponential fog density to use. Higher values result in a more dense fog. + The [i]exponential[/i] fog density to use. Higher values result in a more dense fog. Fog rendering is exponential as in real life. </member> <member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false"> If [code]true[/code], fog effects are enabled. @@ -292,13 +292,15 @@ The [Color] of the volumetric fog when interacting with lights. Mist and fog have an albedo close to [code]Color(1, 1, 1, 1)[/code] while smoke has a darker albedo. </member> <member name="volumetric_fog_ambient_inject" type="float" setter="set_volumetric_fog_ambient_inject" getter="get_volumetric_fog_ambient_inject" default="0.0"> - Scales the strength of ambient light used in the volumetric fog. A value of [code]0[/code] means that ambient light will not impact the volumetric fog. + Scales the strength of ambient light used in the volumetric fog. A value of [code]0.0[/code] means that ambient light will not impact the volumetric fog. [member volumetric_fog_ambient_inject] has a small performance cost when set above [code]0.0[/code]. + [b]Note:[/b] This has no visible effect if [member volumetric_fog_density] is [code]0.0[/code] or if [member volumetric_fog_albedo] is a fully black color. </member> <member name="volumetric_fog_anisotropy" type="float" setter="set_volumetric_fog_anisotropy" getter="get_volumetric_fog_anisotropy" default="0.2"> - The direction of scattered light as it goes through the volumetric fog. A value close [code]1[/code] means almost all light is scattered forward. A value close to [code]0[/code] means light is scattered equally in all directions. A value close to [code]-1[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions. + The direction of scattered light as it goes through the volumetric fog. A value close to [code]1.0[/code] means almost all light is scattered forward. A value close to [code]0.0[/code] means light is scattered equally in all directions. A value close to [code]-1.0[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions. </member> <member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.05"> - The base density of the volumetric fog. Set this to the lowest density you want to have globally. + The base [i]exponential[/i] density of the volumetric fog. Set this to the lowest density you want to have globally. [FogVolume]s can be used to add to or subtract from this density in specific areas. Fog rendering is exponential as in real life. + A value of [code]0.0[/code] disables global volumetric fog while allowing [FogVolume]s to display volumetric fog in specific areas. </member> <member name="volumetric_fog_detail_spread" type="float" setter="set_volumetric_fog_detail_spread" getter="get_volumetric_fog_detail_spread" default="2.0"> The distribution of size down the length of the froxel buffer. A higher value compresses the froxels closer to the camera and places more detail closer to the camera. @@ -311,22 +313,25 @@ </member> <member name="volumetric_fog_enabled" type="bool" setter="set_volumetric_fog_enabled" getter="is_volumetric_fog_enabled" default="false"> Enables the volumetric fog effect. Volumetric fog uses a screen-aligned froxel buffer to calculate accurate volumetric scattering in the short to medium range. Volumetric fog interacts with [FogVolume]s and lights to calculate localized and global fog. Volumetric fog uses a PBR single-scattering model based on extinction, scattering, and emission which it exposes to users as density, albedo, and emission. + [b]Note:[/b] Volumetric fog is only available in the forward plus renderer. It is not available in the mobile renderer or the compatibility renderer. </member> <member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="1.0"> - Scales the strength of Global Illumination used in the volumetric fog. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog. + Scales the strength of Global Illumination used in the volumetric fog's albedo color. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog. [member volumetric_fog_gi_inject] has a small performance cost when set above [code]0.0[/code]. + [b]Note:[/b] This has no visible effect if [member volumetric_fog_density] is [code]0.0[/code] or if [member volumetric_fog_albedo] is a fully black color. [b]Note:[/b] Only [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) are taken into account when using [member volumetric_fog_gi_inject]. Global illumination from [LightmapGI], [ReflectionProbe] and SSIL (see [member ssil_enabled]) will be ignored by volumetric fog. </member> <member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0"> - The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible. + The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible. See also [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth]. </member> <member name="volumetric_fog_sky_affect" type="float" setter="set_volumetric_fog_sky_affect" getter="get_volumetric_fog_sky_affect" default="1.0"> The factor to use when affecting the sky with volumetric fog. [code]1.0[/code] means that volumetric fog can fully obscure the sky. Lower values reduce the impact of volumetric fog on sky rendering, with [code]0.0[/code] not affecting sky rendering at all. + [b]Note:[/b] [member volumetric_fog_sky_affect] also affects [FogVolume]s, even if [member volumetric_fog_density] is [code]0.0[/code]. If you notice [FogVolume]s are disappearing when looking towards the sky, set [member volumetric_fog_sky_affect] to [code]1.0[/code]. </member> <member name="volumetric_fog_temporal_reprojection_amount" type="float" setter="set_volumetric_fog_temporal_reprojection_amount" getter="get_volumetric_fog_temporal_reprojection_amount" default="0.9"> The amount by which to blend the last frame with the current frame. A higher number results in smoother volumetric fog, but makes "ghosting" much worse. A lower value reduces ghosting but can result in the per-frame temporal jitter becoming visible. </member> <member name="volumetric_fog_temporal_reprojection_enabled" type="bool" setter="set_volumetric_fog_temporal_reprojection_enabled" getter="is_volumetric_fog_temporal_reprojection_enabled" default="true"> - Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal, however it does lead to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast. + Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal; however, it leads to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast. Short-lived dynamic lighting effects should have [member Light3D.light_volumetric_fog_energy] set to [code]0.0[/code] to avoid ghosting. </member> </members> <constants> diff --git a/doc/classes/File.xml b/doc/classes/FileAccess.xml index 76c6a4871c..adc0f4c3dd 100644 --- a/doc/classes/File.xml +++ b/doc/classes/FileAccess.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="File" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="FileAccess" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Type to handle file reading and writing operations. </brief_description> @@ -9,39 +9,42 @@ [codeblocks] [gdscript] func save(content): - var file = File.new() - file.open("user://save_game.dat", File.WRITE) + var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE) file.store_string(content) - file.close() func load(): - var file = File.new() - file.open("user://save_game.dat", File.READ) + var file = FileAccess.open("user://save_game.dat", FileAccess.READ) var content = file.get_as_text() - file.close() return content [/gdscript] [csharp] public void Save(string content) { - var file = new File(); - file.Open("user://save_game.dat", File.ModeFlags.Write); + using var file = FileAccess.Open("user://save_game.dat", File.ModeFlags.Write); file.StoreString(content); - file.Close(); } public string Load() { - var file = new File(); - file.Open("user://save_game.dat", File.ModeFlags.Read); + using var file = FileAccess.Open("user://save_game.dat", File.ModeFlags.Read); string content = file.GetAsText(); - file.Close(); return content; } [/csharp] [/codeblocks] In the example above, the file will be saved in the user data folder as specified in the [url=$DOCS_URL/tutorials/io/data_paths.html]Data paths[/url] documentation. - [b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [File] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package. + There is no method to close a file in order to free it from use. Instead, [FileAccess] will close when it's freed, which happens when it goes out of scope or when it gets assigned with [code]null[/code]. In C# the reference must be disposed after we are done using it, this can be done with the [code]using[/code] statement or calling the [code]Dispose[/code] method directly. + [codeblocks] + [gdscript] + var file = FileAccess.open("res://something") # File is opened and locked for use. + file = null # File is closed. + [/gdscript] + [csharp] + using var file = FileAccess.Open("res://something"); // File is opened and locked for use. + // The using statement calls Dispose when going out of scope. + [/csharp] + [/codeblocks] + [b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [FileAccess] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package. [b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [b]Alt + F4[/b]). If you stop the project execution by pressing [b]F8[/b] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals. </description> <tutorials> @@ -49,12 +52,6 @@ <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link> </tutorials> <methods> - <method name="close"> - <return type="void" /> - <description> - Closes the currently opened file and prevents subsequent read/write operations. Use [method flush] to persist the data to disk without closing the file. - </description> - </method> <method name="eof_reached" qualifiers="const"> <return type="bool" /> <description> @@ -80,12 +77,13 @@ <description> Returns [code]true[/code] if the file exists in the given path. [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. See [method ResourceLoader.exists] for an alternative approach that takes resource remapping into account. + For a non-static, relative equivalent, use [method DirAccess.file_exists]. </description> </method> <method name="flush"> <return type="void" /> <description> - Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file using [method close]. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully. + Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully. [b]Note:[/b] Only call [method flush] when you actually need it. Otherwise, it will decrease performance due to constant disk writes. </description> </method> @@ -174,20 +172,26 @@ Text is interpreted as being UTF-8 encoded. </description> </method> - <method name="get_md5" qualifiers="const"> + <method name="get_md5" qualifiers="static"> <return type="String" /> <param index="0" name="path" type="String" /> <description> Returns an MD5 String representing the file at the given path or an empty [String] on failure. </description> </method> - <method name="get_modified_time" qualifiers="const"> + <method name="get_modified_time" qualifiers="static"> <return type="int" /> <param index="0" name="file" type="String" /> <description> Returns the last time the [param file] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton. </description> </method> + <method name="get_open_error" qualifiers="static"> + <return type="int" enum="Error" /> + <description> + Returns the result of the last [method open] call in the current thread. + </description> + </method> <method name="get_pascal_string"> <return type="String" /> <description> @@ -219,7 +223,7 @@ Returns the next bits from the file as a floating-point number. </description> </method> - <method name="get_sha256" qualifiers="const"> + <method name="get_sha256" qualifiers="static"> <return type="String" /> <param index="0" name="path" type="String" /> <description> @@ -240,41 +244,45 @@ Returns [code]true[/code] if the file is currently opened. </description> </method> - <method name="open"> - <return type="int" enum="Error" /> + <method name="open" qualifiers="static"> + <return type="FileAccess" /> <param index="0" name="path" type="String" /> - <param index="1" name="flags" type="int" enum="File.ModeFlags" /> + <param index="1" name="flags" type="int" enum="FileAccess.ModeFlags" /> <description> - Opens the file for writing or reading, depending on the flags. + Creates a new [FileAccess] object and opens the file for writing or reading, depending on the flags. + Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred. </description> </method> - <method name="open_compressed"> - <return type="int" enum="Error" /> + <method name="open_compressed" qualifiers="static"> + <return type="FileAccess" /> <param index="0" name="path" type="String" /> - <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" /> - <param index="2" name="compression_mode" type="int" enum="File.CompressionMode" default="0" /> + <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" /> + <param index="2" name="compression_mode" type="int" enum="FileAccess.CompressionMode" default="0" /> <description> - Opens a compressed file for reading or writing. + Creates a new [FileAccess] object and opens a compressed file for reading or writing. [b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround. + Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred. </description> </method> - <method name="open_encrypted"> - <return type="int" enum="Error" /> + <method name="open_encrypted" qualifiers="static"> + <return type="FileAccess" /> <param index="0" name="path" type="String" /> - <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" /> + <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" /> <param index="2" name="key" type="PackedByteArray" /> <description> - Opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it. + Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it. [b]Note:[/b] The provided key must be 32 bytes long. + Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred. </description> </method> - <method name="open_encrypted_with_pass"> - <return type="int" enum="Error" /> + <method name="open_encrypted_with_pass" qualifiers="static"> + <return type="FileAccess" /> <param index="0" name="path" type="String" /> - <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" /> + <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" /> <param index="2" name="pass" type="String" /> <description> - Opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it. + Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it. + Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred. </description> </method> <method name="seek"> @@ -432,7 +440,7 @@ </method> </methods> <members> - <member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian" default="false"> + <member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian"> If [code]true[/code], the file is read with big-endian [url=https://en.wikipedia.org/wiki/Endianness]endianness[/url]. If [code]false[/code], the file is read with little-endian endianness. If in doubt, leave this to [code]false[/code] as most files are written with little-endian endianness. [b]Note:[/b] [member big_endian] is only about the file format, not the CPU type. The CPU endianness doesn't affect the default endianness for files written. [b]Note:[/b] This is always reset to [code]false[/code] whenever you open the file. Therefore, you must set [member big_endian] [i]after[/i] opening the file, not before. diff --git a/doc/classes/FogMaterial.xml b/doc/classes/FogMaterial.xml index e63d4ddf3e..7428d6169a 100644 --- a/doc/classes/FogMaterial.xml +++ b/doc/classes/FogMaterial.xml @@ -5,27 +5,28 @@ </brief_description> <description> A [Material] resource that can be used by [FogVolume]s to draw volumetric effects. + If you need more advanced effects, use a custom [url=$DOCS_URL/tutorials/shaders/shader_reference/fog_shader.html]fog shader[/url]. </description> <tutorials> </tutorials> <members> <member name="albedo" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)"> - Sets the single-scattering [Color] of the [FogVolume]. Internally [member albedo] is converted into single-scattering which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo]. + The single-scattering [Color] of the [FogVolume]. Internally, [member albedo] is converted into single-scattering, which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo]. </member> <member name="density" type="float" setter="set_density" getter="get_density" default="1.0"> - Sets the density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes. + The density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes. Negative values can be used to subtract fog from other [FogVolume]s or global volumetric fog. </member> <member name="density_texture" type="Texture3D" setter="set_density_texture" getter="get_density_texture"> - Sets a 3D texture that is used to scale the [member density] of the [FogVolume]. + The 3D texture that is used to scale the [member density] of the [FogVolume]. This can be used to vary fog density within the [FogVolume] with any kind of static pattern. For animated effects, consider using a custom [url=$DOCS_URL/tutorials/shaders/shader_reference/fog_shader.html]fog shader[/url]. </member> <member name="edge_fade" type="float" setter="set_edge_fade" getter="get_edge_fade" default="0.1"> - Sets the hardness of the edges of the [FogVolume]. A higher number will result in softer edges while a lower number will result in harder edges. + The hardness of the edges of the [FogVolume]. A higher value will result in softer edges, while a lower value will result in harder edges. </member> <member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color(0, 0, 0, 1)"> - Sets the [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources. + The [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources. </member> <member name="height_falloff" type="float" setter="set_height_falloff" getter="get_height_falloff" default="0.0"> - Sets the rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume]. + The rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0.0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume]. </member> </members> </class> diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml index 3f2ee3035c..d9fa2e6ebb 100644 --- a/doc/classes/FogVolume.xml +++ b/doc/classes/FogVolume.xml @@ -4,22 +4,23 @@ A node used to add local fog with the volumetric fog effect. </brief_description> <description> - [FogVolume]s are used to add localized fog into the global volumetric fog effect. + [FogVolume]s are used to add localized fog into the global volumetric fog effect. [FogVolume]s can also remove volumetric fog from specific areas if using a [FogMaterial] with a negative [member FogMaterial.density]. Performance of [FogVolume]s is directly related to their relative size on the screen and the complexity of their attached [FogMaterial]. It is best to keep [FogVolume]s relatively small and simple where possible. + [b]Note:[/b] [FogVolume]s only have a visible effect if [member Environment.volumetric_fog_enabled] is [code]true[/code]. If you don't want fog to be globally visible (but only within [FogVolume] nodes), set [member Environment.volumetric_fog_density] to [code]0.0[/code]. </description> <tutorials> </tutorials> <members> <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> - Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. + The size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. [b]Note:[/b] Thin fog volumes may appear to flicker when the camera moves or rotates. This can be alleviated by increasing [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth] (at a performance cost) or by decreasing [member Environment.volumetric_fog_length] (at no performance cost, but at the cost of lower fog range). Alternatively, the [FogVolume] can be made thicker and use a lower density in the [member material]. [b]Note:[/b] If [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_CONE] or [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], the cone/cylinder will be adjusted to fit within the extents. Non-uniform scaling of cone/cylinder shapes via the [member extents] property is not supported, but you can scale the [FogVolume] node instead. </member> <member name="material" type="Material" setter="set_material" getter="get_material"> - Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial]. + The [Material] used by the [FogVolume]. Can be either a built-in [FogMaterial] or a custom [ShaderMaterial]. </member> <member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="3"> - Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. + The shape of the [FogVolume]. This can be set to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. </member> </members> </class> diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index ad3a16afbb..6a42b62bcf 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -228,9 +228,15 @@ <description> Returns the size of a bounding box of a single-line string, taking kerning and advance into account. See also [method get_multiline_string_size] and [method draw_string]. For example, to get the string size as displayed by a single-line Label, use: - [codeblock] + [codeblocks] + [gdscript] var string_size = $Label.get_theme_font("font").get_string_size($Label.text, HORIZONTAL_ALIGNMENT_LEFT, -1, $Label.get_theme_font_size("font_size")) - [/codeblock] + [/gdscript] + [csharp] + Label label = GetNode<Label>("Label"); + Vector2 stringSize = label.GetThemeFont("font").GetStringSize(label.Text, HorizontalAlignment.Left, -1, label.GetThemeFontSize("font_size")); + [/csharp] + [/codeblocks] [b]Note:[/b] Real height of the string is context-dependent and can be significantly different from the value returned by [method get_height]. </description> </method> diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml index 392ca2cabb..e613ab1a55 100644 --- a/doc/classes/Geometry2D.xml +++ b/doc/classes/Geometry2D.xml @@ -126,7 +126,7 @@ <return type="Dictionary" /> <param index="0" name="sizes" type="PackedVector2Array" /> <description> - Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is an array of [Vector2] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2]. + Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is a [PackedVector2Array] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2i]. </description> </method> <method name="merge_polygons"> diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml index 52d4fce28f..706ee30963 100644 --- a/doc/classes/HMACContext.xml +++ b/doc/classes/HMACContext.xml @@ -32,22 +32,22 @@ public class CryptoNode : Node { private HMACContext ctx = new HMACContext(); + public override void _Ready() { - PackedByteArray key = String("supersecret").to_utf8(); - Error err = ctx.Start(HashingContext.HASH_SHA256, key); - GD.Assert(err == OK); - PackedByteArray msg1 = String("this is ").to_utf8(); - PackedByteArray msg2 = String("super duper secret").to_utf8(); + byte[] key = "supersecret".ToUTF8(); + Error err = ctx.Start(HashingContext.HashType.Sha256, key); + Debug.Assert(err == Error.Ok); + byte[] msg1 = "this is ".ToUTF8(); + byte[] msg2 = "super duper secret".ToUTF8(); err = ctx.Update(msg1); - GD.Assert(err == OK); + Debug.Assert(err == Error.Ok); err = ctx.Update(msg2); - GD.Assert(err == OK); - PackedByteArray hmac = ctx.Finish(); + Debug.Assert(err == Error.Ok); + byte[] hmac = ctx.Finish(); GD.Print(hmac.HexEncode()); } } - [/csharp] [/codeblocks] </description> diff --git a/doc/classes/ImageFormatLoader.xml b/doc/classes/ImageFormatLoader.xml new file mode 100644 index 0000000000..c6b1ec922a --- /dev/null +++ b/doc/classes/ImageFormatLoader.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ImageFormatLoader" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Base class to add support for specific image formats. + </brief_description> + <description> + The engine supports multiple image formats out of the box (PNG, SVG, JPEG, WebP to name a few), but you can choose to implement support for additional image formats by extending [ImageFormatLoaderExtension]. + </description> + <tutorials> + </tutorials> + <constants> + <constant name="FLAG_NONE" value="0" enum="LoaderFlags" is_bitfield="true"> + </constant> + <constant name="FLAG_FORCE_LINEAR" value="1" enum="LoaderFlags" is_bitfield="true"> + </constant> + <constant name="FLAG_CONVERT_COLORS" value="2" enum="LoaderFlags" is_bitfield="true"> + </constant> + </constants> +</class> diff --git a/doc/classes/ImageFormatLoaderExtension.xml b/doc/classes/ImageFormatLoaderExtension.xml new file mode 100644 index 0000000000..b2a7ebc60f --- /dev/null +++ b/doc/classes/ImageFormatLoaderExtension.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ImageFormatLoaderExtension" inherits="ImageFormatLoader" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Base class for creating [ImageFormatLoader] extensions (adding support for extra image formats). + </brief_description> + <description> + The engine supports multiple image formats out of the box (PNG, SVG, JPEG, WebP to name a few), but you can choose to implement support for additional image formats by extending this class. + Be sure to respect the documented return types and values. You should create an instance of it, and call [method add_format_loader] to register that loader during the initializaiton phase. + </description> + <tutorials> + </tutorials> + <methods> + <method name="_get_recognized_extensions" qualifiers="virtual const"> + <return type="PackedStringArray" /> + <description> + Returns the list of file extensions for this image format. Files with the given extentions will be treated as image file and loaded using this class. + </description> + </method> + <method name="_load_image" qualifiers="virtual"> + <return type="int" enum="Error" /> + <param index="0" name="image" type="Image" /> + <param index="1" name="fileaccess" type="FileAccess" /> + <param index="2" name="flags" type="int" enum="ImageFormatLoader.LoaderFlags" /> + <param index="3" name="scale" type="float" /> + <description> + Loads the content of [param fileaccess] into the provided [param image]. + </description> + </method> + <method name="add_format_loader"> + <return type="void" /> + <description> + Add this format loader to the engine, allowing it to recognize the file extensions returned by [method _get_recognized_extensions]. + </description> + </method> + <method name="remove_format_loader"> + <return type="void" /> + <description> + Remove this format loader from the engine. + </description> + </method> + </methods> +</class> diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml index f5b338542b..f5786f070a 100644 --- a/doc/classes/ImageTextureLayered.xml +++ b/doc/classes/ImageTextureLayered.xml @@ -11,6 +11,8 @@ <return type="int" enum="Error" /> <param index="0" name="images" type="Image[]" /> <description> + Creates an [ImageTextureLayered] from an array of [Image]s. The first image decides the width, height, image format and mipmapping setting. The other images must have the same width, height, image format and mipmapping setting. + Each [Image] represents one [code]layer[/code]. </description> </method> <method name="update_layer"> @@ -18,6 +20,10 @@ <param index="0" name="image" type="Image" /> <param index="1" name="layer" type="int" /> <description> + Replaces the existing [Image] data at the given [code]layer[/code] with this new image. + The given [Image] must have the same width, height, image format and mipmapping setting (a [code]bool[/code] value) as the rest of the referenced images. + If the image format is unsupported, it will be decompressed and converted to a similar and supported [enum Image.Format]. + The update is immediate: synced with the draw. </description> </method> </methods> diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 46e46cc164..125d016632 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -6,7 +6,7 @@ <description> The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network. [method stringify] is used to convert any data type into a JSON string. - [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. + [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [member data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. [b]Example[/b] [codeblock] var data_to_send = ["a", "b", "c"] @@ -16,7 +16,7 @@ # Retrieve data var error = json.parse(json_string) if error == OK: - var data_received = json.get_data() + var data_received = json.data if typeof(data_received) == TYPE_ARRAY: print(data_received) # Prints array else: @@ -28,17 +28,15 @@ [codeblock] var data = JSON.parse_string(json_string) # Returns null if parsing failed. [/codeblock] + [b]Note:[/b] Both parse methods do not fully comply with the JSON specification: + - Trailing commas in arrays or objects are ignored, instead of causing a parser error. + - New line and tab characters are accepted in string literals, and are treated like their corresponding escape sequences [code]\n[/code] and [code]\t[/code]. + - Numbers are parsed using [method String.to_float] which is generally more lax than the JSON specification. + - Certain errors, such as invalid Unicode sequences, do not cause a parser error. Instead, the string is cleansed and an error is logged to the console. </description> <tutorials> </tutorials> <methods> - <method name="get_data" qualifiers="const"> - <return type="Variant" /> - <description> - Returns the [Variant] containing the data of a successful [method parse]. - [b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called. - </description> - </method> <method name="get_error_line" qualifiers="const"> <return type="int" /> <description> @@ -56,7 +54,7 @@ <param index="0" name="json_string" type="String" /> <description> Attempts to parse the [param json_string] provided. - Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. + Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] 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. </description> </method> @@ -118,4 +116,9 @@ </description> </method> </methods> + <members> + <member name="data" type="Variant" setter="set_data" getter="get_data" default="null"> + Contains the parsed JSON data in [Variant] form. + </member> + </members> </class> diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml index dd8c7be489..53dae1a8e6 100644 --- a/doc/classes/LightmapGI.xml +++ b/doc/classes/LightmapGI.xml @@ -17,7 +17,7 @@ <member name="bias" type="float" setter="set_bias" getter="get_bias" default="0.0005"> The bias to use when computing shadows. Increasing [member bias] can fix shadow acne on the resulting baked lightmap, but can introduce peter-panning (shadows not connecting to their casters). Real-time [Light3D] shadows are not affected by this [member bias] property. </member> - <member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="1"> + <member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="3"> Number of light bounces that are taken into account during baking. Higher values result in brighter, more realistic lighting, at the cost of longer bake times. If set to [code]0[/code], only environment lighting, direct light and emissive lighting is baked. </member> <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes"> @@ -36,10 +36,10 @@ <member name="environment_custom_sky" type="Sky" setter="set_environment_custom_sky" getter="get_environment_custom_sky"> The sky to use as a source of environment lighting. Only effective if [member environment_mode] is [constant ENVIRONMENT_MODE_CUSTOM_SKY]. </member> - <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="0"> + <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="1"> The environment mode to use when baking lightmaps. </member> - <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="0"> + <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="2"> The level of subdivision to use when automatically generating [LightmapProbe]s for dynamic object lighting. Higher values result in more accurate indirect lighting on dynamic objects, at the cost of longer bake times and larger file sizes. [b]Note:[/b] Automatically generated [LightmapProbe]s are not visible as nodes in the Scene tree dock, and cannot be modified this way after they are generated. [b]Note:[/b] Regardless of [member generate_probes_subdiv], direct lighting on dynamic objects is always applied using [Light3D] nodes in real-time. diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index d8ad65082f..d9732da3a3 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -179,9 +179,14 @@ <return type="Tween" /> <description> Creates a new [Tween] and binds it to this node. This is equivalent of doing: - [codeblock] + [codeblocks] + [gdscript] get_tree().create_tween().bind_node(self) - [/codeblock] + [/gdscript] + [csharp] + GetTree().CreateTween().BindNode(this); + [/csharp] + [/codeblocks] </description> </method> <method name="duplicate" qualifiers="const"> @@ -267,13 +272,24 @@ Returns an array listing the groups that the node is a member of. [b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs. [b]Note:[/b] The engine uses some group names internally (all starting with an underscore). To avoid conflicts with internal groups, do not add custom groups whose name starts with an underscore. To exclude internal groups while looping over [method get_groups], use the following snippet: - [codeblock] + [codeblocks] + [gdscript] # Stores the node's non-internal groups only (as an array of Strings). var non_internal_groups = [] for group in get_groups(): if not group.begins_with("_"): non_internal_groups.push_back(group) - [/codeblock] + [/gdscript] + [csharp] + // Stores the node's non-internal groups only (as a List of strings). + List<string> nonInternalGroups = new List<string>(); + foreach (string group in GetGroups()) + { + if (!group.BeginsWith("_")) + nonInternalGroups.Add(group); + } + [/csharp] + [/codeblocks] </description> </method> <method name="get_index" qualifiers="const"> diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index c8e2f1ac68..96ce10745d 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -331,6 +331,10 @@ <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="43"> Node3D nodes receives this notification when their visibility changes. </constant> + <constant name="NOTIFICATION_LOCAL_TRANSFORM_CHANGED" value="44"> + Node3D nodes receives this notification when their local transform changes. This is not received when the transform of a parent node is changed. + In order for [constant NOTIFICATION_LOCAL_TRANSFORM_CHANGED] to work, users first need to ask for it, with [method set_notify_local_transform]. + </constant> <constant name="ROTATION_EDIT_MODE_EULER" value="0" enum="RotationEditMode"> </constant> <constant name="ROTATION_EDIT_MODE_QUATERNION" value="1" enum="RotationEditMode"> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 059766656f..be7bacd994 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -216,6 +216,15 @@ Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path. </description> </method> + <method name="get_distribution_name" qualifiers="const"> + <return type="String" /> + <description> + Returns the name of the distribution for Linux and BSD platforms (e.g. Ubuntu, Manjaro, OpenBSD, etc.). + Returns the same value as [method get_name] for stock Android ROMs, but attempts to return the custom ROM name for popular Android derivatives such as LineageOS. + Returns the same value as [method get_name] for other platforms. + [b]Note:[/b] This method is not supported on the web platform. It returns an empty string. + </description> + </method> <method name="get_environment" qualifiers="const"> <return type="String" /> <param index="0" name="variable" type="String" /> @@ -430,6 +439,18 @@ Not to be confused with [method get_data_dir], which returns the [i]global[/i] (non-project-specific) user home directory. </description> </method> + <method name="get_version" qualifiers="const"> + <return type="String" /> + <description> + Returns the exact production and build version of the operating system. This is different from the branded version used in marketing. This helps to distinguish between different releases of operating systems, including minor versions, and insider and custom builds. + For Windows, the major and minor version are returned, as well as the build number. For example, the returned string can look like [code]10.0.9926[/code] for a build of Windows 10, and it can look like [code]6.1.7601[/code] for a build of Windows 7 SP1. + For rolling distributions, such as Arch Linux, an empty string is returned. + For macOS and iOS, the major and minor version are returned, as well as the patch number. + For UWP, the device family version is returned. + For Android, the SDK version and the incremental build number are returned. If it's a custom ROM, it attempts to return its version instead. + [b]Note:[/b] This method is not supported on the web platform. It returns an empty string. + </description> + </method> <method name="has_environment" qualifiers="const"> <return type="bool" /> <param index="0" name="variable" type="String" /> @@ -501,13 +522,19 @@ <return type="int" enum="Error" /> <param index="0" name="path" type="String" /> <description> - Moves the file or directory to the system's recycle bin. See also [method Directory.remove]. + Moves the file or directory to the system's recycle bin. See also [method DirAccess.remove]. The method takes only global paths, so you may need to use [method ProjectSettings.globalize_path]. Do not use it for files in [code]res://[/code] as it will not work in exported project. [b]Note:[/b] If the user has disabled the recycle bin on their system, the file will be permanently deleted instead. - [codeblock] + [codeblocks] + [gdscript] var file_to_remove = "user://slot1.sav" OS.move_to_trash(ProjectSettings.globalize_path(file_to_remove)) - [/codeblock] + [/gdscript] + [csharp] + var fileToRemove = "user://slot1.sav"; + OS.MoveToTrash(ProjectSettings.GlobalizePath(fileToRemove)); + [/csharp] + [/codeblocks] </description> </method> <method name="open_midi_inputs"> diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index efb559522a..ccf012f82c 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -65,7 +65,7 @@ <return type="PackedByteArray" /> <param index="0" name="compression_mode" type="int" default="0" /> <description> - Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. + Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants. </description> </method> <method name="count" qualifiers="const"> @@ -173,7 +173,7 @@ <param index="0" name="buffer_size" type="int" /> <param index="1" name="compression_mode" type="int" default="0" /> <description> - Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants. + Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants. </description> </method> <method name="decompress_dynamic" qualifiers="const"> @@ -181,7 +181,7 @@ <param index="0" name="max_output_size" type="int" /> <param index="1" name="compression_mode" type="int" default="0" /> <description> - Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b] + Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b] This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning. GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned. </description> diff --git a/doc/classes/PanoramaSkyMaterial.xml b/doc/classes/PanoramaSkyMaterial.xml index 21c7f29585..0c27037f28 100644 --- a/doc/classes/PanoramaSkyMaterial.xml +++ b/doc/classes/PanoramaSkyMaterial.xml @@ -4,9 +4,9 @@ A [Material] used with [Sky] to draw a background texture. </brief_description> <description> - A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cube map. + A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cubemap. Using an HDR panorama is strongly recommended for accurate, high-quality reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) image formats for this purpose. - You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map. + You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map. </description> <tutorials> </tutorials> diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml index e8d7ac9920..59660b4de5 100644 --- a/doc/classes/PhysicsBody2D.xml +++ b/doc/classes/PhysicsBody2D.xml @@ -28,11 +28,13 @@ <param index="0" name="distance" type="Vector2" /> <param index="1" name="test_only" type="bool" default="false" /> <param index="2" name="safe_margin" type="float" default="0.08" /> + <param index="3" name="recovery_as_collision" type="bool" default="false" /> <description> Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. Returns a [KinematicCollision2D], which contains information about the collision when stopped, or when touching another body along the motion. If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details). + If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is used e.g. by [CharacterBody2D] for improving floor detection during floor snapping. </description> </method> <method name="remove_collision_exception_with"> @@ -48,11 +50,13 @@ <param index="1" name="distance" type="Vector2" /> <param index="2" name="collision" type="KinematicCollision2D" default="null" /> <param index="3" name="safe_margin" type="float" default="0.08" /> + <param index="4" name="recovery_as_collision" type="bool" default="false" /> <description> Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. [param collision] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details). + If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is useful for checking whether the body would [i]touch[/i] any other bodies. </description> </method> </methods> diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index 310671274f..bf7882a1ea 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -35,12 +35,14 @@ <param index="0" name="distance" type="Vector3" /> <param index="1" name="test_only" type="bool" default="false" /> <param index="2" name="safe_margin" type="float" default="0.001" /> - <param index="3" name="max_collisions" type="int" default="1" /> + <param index="3" name="recovery_as_collision" type="bool" default="false" /> + <param index="4" name="max_collisions" type="int" default="1" /> <description> Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision when stopped, or when touching another body along the motion. If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details). + If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is used e.g. by [CharacterBody3D] for improving floor detection during floor snapping. [param max_collisions] allows to retrieve more than one collision result. </description> </method> @@ -65,12 +67,14 @@ <param index="1" name="distance" type="Vector3" /> <param index="2" name="collision" type="KinematicCollision3D" default="null" /> <param index="3" name="safe_margin" type="float" default="0.001" /> - <param index="4" name="max_collisions" type="int" default="1" /> + <param index="4" name="recovery_as_collision" type="bool" default="false" /> + <param index="5" name="max_collisions" type="int" default="1" /> <description> Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. [param collision] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details). + If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is useful for checking whether the body would [i]touch[/i] any other bodies. [param max_collisions] allows to retrieve more than one collision result. </description> </method> diff --git a/doc/classes/PhysicsTestMotionParameters2D.xml b/doc/classes/PhysicsTestMotionParameters2D.xml index 4f2b62f2d9..d8f96511dd 100644 --- a/doc/classes/PhysicsTestMotionParameters2D.xml +++ b/doc/classes/PhysicsTestMotionParameters2D.xml @@ -29,8 +29,8 @@ Motion vector to define the length and direction of the motion to test. </member> <member name="recovery_as_collision" type="bool" setter="set_recovery_as_collision_enabled" getter="is_recovery_as_collision_enabled" default="false"> - If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [method CharacterBody2D.move_and_slide] for improving floor detection when floor snapping is disabled. - If set to [code]false[/code], only collisions resulting from the motion are reported; this is used e.g. by [method PhysicsBody2D.move_and_collide]. + If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [CharacterBody2D] for improving floor detection during floor snapping. + If set to [code]false[/code], only collisions resulting from the motion are reported, which is generally the desired behaviour. </member> </members> </class> diff --git a/doc/classes/PhysicsTestMotionParameters3D.xml b/doc/classes/PhysicsTestMotionParameters3D.xml index 5b07796a10..e8f80ae131 100644 --- a/doc/classes/PhysicsTestMotionParameters3D.xml +++ b/doc/classes/PhysicsTestMotionParameters3D.xml @@ -32,8 +32,8 @@ Motion vector to define the length and direction of the motion to test. </member> <member name="recovery_as_collision" type="bool" setter="set_recovery_as_collision_enabled" getter="is_recovery_as_collision_enabled" default="false"> - If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [method CharacterBody3D.move_and_slide] for improving floor detection when floor snapping is disabled. - If set to [code]false[/code], only collisions resulting from the motion are detected; this is used e.g. by [method PhysicsBody3D.move_and_collide]. + If set to [code]true[/code], any depenetration from the recovery phase is reported as a collision; this is used e.g. by [CharacterBody3D] for improving floor detection during floor snapping. + If set to [code]false[/code], only collisions resulting from the motion are reported, which is generally the desired behaviour. </member> </members> </class> diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml index 564b6fe743..1dceac70b0 100644 --- a/doc/classes/PlaneMesh.xml +++ b/doc/classes/PlaneMesh.xml @@ -31,10 +31,10 @@ [PlaneMesh] will face the positive X-axis. </constant> <constant name="FACE_Y" value="1" enum="Orientation"> - [PlaneMesh] will face the positive Y-axis. This matches the behaviour of the [PlaneMesh] in Godot 3.x. + [PlaneMesh] will face the positive Y-axis. This matches the behavior of the [PlaneMesh] in Godot 3.x. </constant> <constant name="FACE_Z" value="2" enum="Orientation"> - [PlaneMesh] will face the positive Z-axis. This matches the behvaiour of the QuadMesh in Godot 3.x. + [PlaneMesh] will face the positive Z-axis. This matches the behavior of the QuadMesh in Godot 3.x. </constant> </constants> </class> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 1f07a13c94..4c2cf330af 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -159,6 +159,15 @@ Sets the order of a configuration value (influences when saved to the config file). </description> </method> + <method name="set_restart_if_changed"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="restart" type="bool" /> + <description> + Sets whether a setting requires restarting the editor to properly take effect. + [b]Note:[/b] This is just a hint to display to the user that the editor must be restarted for changes to take effect. Enabling [method set_restart_if_changed] does [i]not[/i] delay the setting being set when changed. + </description> + </method> <method name="set_setting"> <return type="void" /> <param index="0" name="name" type="String" /> @@ -1705,13 +1714,6 @@ If [code]true[/code], performs a previous depth pass before rendering 3D materials. This increases performance significantly in scenes with high overdraw, when complex materials and lighting are used. However, in scenes with few occluded surfaces, the depth prepass may reduce performance. If your game is viewed from a fixed angle that makes it easy to avoid overdraw (such as top-down or side-scrolling perspective), consider disabling the depth prepass to improve performance. This setting can be changed at run-time to optimize performance depending on the scene currently being viewed. [b]Note:[/b] Only supported when using the Vulkan Clustered backend or the OpenGL backend. When using Vulkan Mobile there is no depth prepass performed. </member> - <member name="rendering/driver/driver_name" type="String" setter="" getter="" default=""vulkan""> - The video driver to use. - [b]Note:[/b] OpenGL support is currently incomplete. Only basic rendering is supported. - [b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument. - [b]FIXME:[/b] No longer valid after DisplayServer split: - In such cases, this property is not updated, so use [code]OS.get_current_video_driver[/code] to query it at run-time. - </member> <member name="rendering/driver/threads/thread_model" type="int" setter="" getter="" default="1"> Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter. </member> @@ -1782,11 +1784,32 @@ Enables filtering of the volumetric fog effect prior to integration. This substantially blurs the fog which reduces fine details but also smooths out harsh edges and aliasing artifacts. Disable when more detail is required. </member> <member name="rendering/environment/volumetric_fog/volume_depth" type="int" setter="" getter="" default="64"> - Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement. + Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement. See also [member Environment.volumetric_fog_length]. </member> <member name="rendering/environment/volumetric_fog/volume_size" type="int" setter="" getter="" default="64"> Base size used to determine size of froxel buffer in the camera X-axis and Y-axis. The final size is scaled by the aspect ratio of the screen, so actual values may differ from what is set. Set a larger size for more detailed fog, set a smaller size for better performance. </member> + <member name="rendering/gl_compatibility/driver" type="String" setter="" getter="" default=""opengl3""> + Sets the driver to be used by the renderer when using the Compatibility renderer. This property can not be edited directly, instead, set the driver using the platform-specific overrides. + </member> + <member name="rendering/gl_compatibility/driver.android" type="String" setter="" getter="" default=""opengl3""> + Android override for [member rendering/gl_compatibility/driver]. + </member> + <member name="rendering/gl_compatibility/driver.ios" type="String" setter="" getter="" default=""opengl3""> + iOS override for [member rendering/gl_compatibility/driver]. + </member> + <member name="rendering/gl_compatibility/driver.linuxbsd" type="String" setter="" getter="" default=""opengl3""> + LinuxBSD override for [member rendering/gl_compatibility/driver]. + </member> + <member name="rendering/gl_compatibility/driver.macos" type="String" setter="" getter="" default=""opengl3""> + macOS override for [member rendering/gl_compatibility/driver]. + </member> + <member name="rendering/gl_compatibility/driver.web" type="String" setter="" getter="" default=""opengl3""> + Web override for [member rendering/gl_compatibility/driver]. + </member> + <member name="rendering/gl_compatibility/driver.windows" type="String" setter="" getter="" default=""opengl3""> + Windows override for [member rendering/gl_compatibility/driver]. + </member> <member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false"> If [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting. [b]Note:[/b] This property is only read when the project starts. To set half-resolution GI at run-time, call [method RenderingServer.gi_set_use_half_resolution] instead. @@ -1947,6 +1970,44 @@ <member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false"> Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support. </member> + <member name="rendering/renderer/rendering_method" type="String" setter="" getter="" default=""forward_plus""> + Sets the renderer that will be used by the project. Options are: + [b]Clustered[/b]: High-end renderer designed for Desktop devices. Has a higher base overhead, but scales well with complex scenes. Not suitable for older devices or mobile. + [b]Mobile[/b]: Modern renderer designed for mobile devices. Has a lower base overhead than Clustered, but does not scale as well to large scenes with many elements. + [b]Compatibility[/b]: Low-end renderer designed for older devices. Based on the limitations of the OpenGL 3.3/ OpenGL ES 3.0 / WebGL 2 APIs. + </member> + <member name="rendering/renderer/rendering_method.mobile" type="String" setter="" getter="" default=""forward_plus""> + Override for [member rendering/renderer/rendering_method] on mobile devices. + </member> + <member name="rendering/renderer/rendering_method.web" type="String" setter="" getter="" default=""gl_compatibility""> + Override for [member rendering/renderer/rendering_method] on web. + </member> + <member name="rendering/rendering_device/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64"> + </member> + <member name="rendering/rendering_device/driver" type="String" setter="" getter="" default=""vulkan""> + Sets the driver to be used by the renderer when using a RenderingDevice-based renderer like the clustered renderer or the mobile renderer. This property can not be edited directly, instead, set the driver using the platform-specific overrides. + </member> + <member name="rendering/rendering_device/driver.android" type="String" setter="" getter="" default=""vulkan""> + Android override for [member rendering/rendering_device/driver]. + </member> + <member name="rendering/rendering_device/driver.ios" type="String" setter="" getter="" default=""vulkan""> + iOS override for [member rendering/rendering_device/driver]. + </member> + <member name="rendering/rendering_device/driver.linuxbsd" type="String" setter="" getter="" default=""vulkan""> + LinuxBSD override for [member rendering/rendering_device/driver]. + </member> + <member name="rendering/rendering_device/driver.macos" type="String" setter="" getter="" default=""vulkan""> + macOS override for [member rendering/rendering_device/driver]. + </member> + <member name="rendering/rendering_device/driver.windows" type="String" setter="" getter="" default=""vulkan""> + Windows override for [member rendering/rendering_device/driver]. + </member> + <member name="rendering/rendering_device/staging_buffer/block_size_kb" type="int" setter="" getter="" default="256"> + </member> + <member name="rendering/rendering_device/staging_buffer/max_size_mb" type="int" setter="" getter="" default="128"> + </member> + <member name="rendering/rendering_device/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64"> + </member> <member name="rendering/scaling_3d/fsr_sharpness" type="float" setter="" getter="" default="0.2"> Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference. </member> @@ -2028,18 +2089,6 @@ <member name="rendering/vrs/texture" type="String" setter="" getter="" default=""""> If [member rendering/vrs/mode] is set to texture, this is the path to default texture loaded as the VRS image. </member> - <member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64"> - </member> - <member name="rendering/vulkan/rendering/back_end" type="int" setter="" getter="" default="0"> - </member> - <member name="rendering/vulkan/rendering/back_end.mobile" type="int" setter="" getter="" default="1"> - </member> - <member name="rendering/vulkan/staging_buffer/block_size_kb" type="int" setter="" getter="" default="256"> - </member> - <member name="rendering/vulkan/staging_buffer/max_size_mb" type="int" setter="" getter="" default="128"> - </member> - <member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64"> - </member> <member name="threading/worker_pool/low_priority_thread_ratio" type="float" setter="" getter="" default="0.3"> </member> <member name="threading/worker_pool/max_threads" type="int" setter="" getter="" default="-1"> diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml new file mode 100644 index 0000000000..7469338ef9 --- /dev/null +++ b/doc/classes/QuadMesh.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="QuadMesh" inherits="PlaneMesh" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Class representing a square mesh facing the camera. + </brief_description> + <description> + Class representing a square [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Y axes; this rotation is more suited for use with billboarded materials. A [QuadMesh] is equivalent to a [PlaneMesh] except its default [member PlaneMesh.orientation] is [constant PlaneMesh.FACE_Z]. + </description> + <tutorials> + <link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link> + <link title="2D in 3D Demo">https://godotengine.org/asset-library/asset/129</link> + </tutorials> + <members> + <member name="orientation" type="int" setter="set_orientation" getter="get_orientation" overrides="PlaneMesh" enum="PlaneMesh.Orientation" default="2" /> + </members> +</class> diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml index b0c9056cbc..8cd701e0d8 100644 --- a/doc/classes/ResourceSaver.xml +++ b/doc/classes/ResourceSaver.xml @@ -62,10 +62,10 @@ Do not save editor-specific metadata (identified by their [code]__editor[/code] prefix). </constant> <constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags" is_bitfield="true"> - Save as big endian (see [member File.big_endian]). + Save as big endian (see [member FileAccess.big_endian]). </constant> <constant name="FLAG_COMPRESS" value="32" enum="SaverFlags" is_bitfield="true"> - Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only available for binary resource types. + Compress the resource on save using [constant FileAccess.COMPRESSION_ZSTD]. Only available for binary resource types. </constant> <constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags" is_bitfield="true"> Take over the paths of the saved subresources (see [method Resource.take_over_path]). diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml index c365e0971b..68834839f3 100644 --- a/doc/classes/ScriptEditorBase.xml +++ b/doc/classes/ScriptEditorBase.xml @@ -19,14 +19,14 @@ <method name="get_base_editor" qualifiers="const"> <return type="Control" /> <description> - Returns the underlying [Control] used for editing scripts. This can be either [CodeEdit] (for text scripts) or [GraphEdit] (for visual scripts). + Returns the underlying [Control] used for editing scripts. For text scripts, this is a [CodeEdit]. </description> </method> </methods> <signals> <signal name="edited_script_changed"> <description> - Emitted after script validation. For visual scripts on modification. + Emitted after script validation. </description> </signal> <signal name="go_to_help"> @@ -37,13 +37,13 @@ </signal> <signal name="name_changed"> <description> - Emitted after script validation or when the edited resource has changed. Not used by visual scripts. + Emitted after script validation or when the edited resource has changed. </description> </signal> <signal name="replace_in_files_requested"> <param index="0" name="text" type="String" /> <description> - Emitted when the user request to find and replace text in the file system. Not used by visual scripts. + Emitted when the user request to find and replace text in the file system. </description> </signal> <signal name="request_help"> @@ -67,7 +67,7 @@ <signal name="search_in_files_requested"> <param index="0" name="text" type="String" /> <description> - Emitted when the user request to search text in the file system. Not used by visual scripts. + Emitted when the user request to search text in the file system. </description> </signal> </signals> diff --git a/doc/classes/StreamPeerBuffer.xml b/doc/classes/StreamPeerBuffer.xml index 4bef9f44b7..f33c38e595 100644 --- a/doc/classes/StreamPeerBuffer.xml +++ b/doc/classes/StreamPeerBuffer.xml @@ -4,7 +4,7 @@ Data buffer stream peer. </brief_description> <description> - Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [File] can be used directly. + Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [FileAccess] can be used directly. A [StreamPeerBuffer] object keeps an internal cursor which is the offset in bytes to the start of the buffer. Get and put operations are performed at the cursor position and will move the cursor accordingly. </description> <tutorials> diff --git a/doc/classes/StreamPeerGZIP.xml b/doc/classes/StreamPeerGZIP.xml new file mode 100644 index 0000000000..71dd36160d --- /dev/null +++ b/doc/classes/StreamPeerGZIP.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="StreamPeerGZIP" inherits="StreamPeer" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Stream peer handling GZIP and deflate compression/decompresison. + </brief_description> + <description> + This class allows to compress or decompress data using GZIP/deflate in a streaming fashion. This is particularly useful when compressing or decompressing files that has to be sent through the network without having to allocate them all in memory. + After starting the stream via [method start_compression] (or [method start_decompression]), calling [method StreamPeer.put_partial_data] on this stream will compress (or decompress) the data, writing it to the internal buffer. Calling [method StreamPeer.get_available_bytes] will return the pending bytes in the internal buffer, and [method StreamPeer.get_partial_data] will retrieve the compressed (or decompressed) bytes from it. When the stream is over, you must call [method finish] to ensure the internal buffer is properly flushed (make sure to call [method StreamPeer.get_available_bytes] on last time to check if more data needs to be read after that). + </description> + <tutorials> + </tutorials> + <methods> + <method name="clear"> + <return type="void" /> + <description> + Clears this stream, resetting the internal state. + </description> + </method> + <method name="finish"> + <return type="int" enum="Error" /> + <description> + Finalizes the stream, compressing or decompressing any buffered chunk left. + </description> + </method> + <method name="start_compression"> + <return type="int" enum="Error" /> + <param index="0" name="use_deflate" type="bool" default="false" /> + <param index="1" name="buffer_size" type="int" default="65535" /> + <description> + Start the stream in compression mode with the given [param buffer_size], if [param use_deflate] is [code]true[/code] uses deflate instead of GZIP. + </description> + </method> + <method name="start_decompression"> + <return type="int" enum="Error" /> + <param index="0" name="use_deflate" type="bool" default="false" /> + <param index="1" name="buffer_size" type="int" default="65535" /> + <description> + Start the stream in decompression mode with the given [param buffer_size], if [param use_deflate] is [code]true[/code] uses deflate instead of GZIP. + </description> + </method> + </methods> +</class> diff --git a/doc/classes/Texture2DArray.xml b/doc/classes/Texture2DArray.xml index 6f059b5fbf..113f37f974 100644 --- a/doc/classes/Texture2DArray.xml +++ b/doc/classes/Texture2DArray.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Texture2DArray" inherits="ImageTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + A single texture resource which consists of multiple, separate images. Each image has the same dimensions and number of mipmap levels. </brief_description> <description> + A Texture2DArray is different from a Texture3D: The Texture2DArray does not support trilinear interpolation between the [Image]s, i.e. no blending. + A Texture2DArray is also different from an [AtlasTexture]: In a Texture2DArray, all images are treated separately. In an atlas, the regions (i.e. the single images) can be of different sizes. Furthermore, you usually need to add a padding around the regions, to prevent accidental UV mapping to more than one region. The same goes for mipmapping: Mipmap chains are handled separately for each layer. In an atlas, the slicing has to be done manually in the fragment shader. </description> <tutorials> </tutorials> diff --git a/doc/classes/TextureLayered.xml b/doc/classes/TextureLayered.xml index 7b528e2082..5e6afcbc5c 100644 --- a/doc/classes/TextureLayered.xml +++ b/doc/classes/TextureLayered.xml @@ -1,10 +1,15 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="TextureLayered" inherits="Texture" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Base class for 3D texture types. + Base class for texture types which contain the data of multiple [Image]s. Each image is of the same size and format. </brief_description> <description> - Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer. + Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. + Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer. + All images need to have the same width, height and number of mipmap levels. + A [TextureLayered] can be loaded with [code]method ResourceFormatLoader.load[/code]. + To create such a texture file yourself, re-import your image files using the Godot Editor import presets. + Internally, Godot maps these files to their respective counterparts in the target rendering driver (GLES3, Vulkan). </description> <tutorials> </tutorials> @@ -72,6 +77,7 @@ <method name="get_layers" qualifiers="const"> <return type="int" /> <description> + Returns the number of referenced [Image]s. </description> </method> <method name="get_width" qualifiers="const"> @@ -83,6 +89,7 @@ <method name="has_mipmaps" qualifiers="const"> <return type="bool" /> <description> + Returns [code]true[/code] if the layers have generated mipmaps. </description> </method> </methods> diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 5186972477..acf900ae55 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -8,42 +8,85 @@ [Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween]; it would be difficult to do the same thing with an [AnimationPlayer] node. Tweens are also more light-weight than [AnimationPlayer], so they are very much suited for simple animations or general tasks that don't require visual tweaking provided by the editor. They can be used in a fire-and-forget manner for some logic that normally would be done by code. You can e.g. make something shoot periodically by using a looped [CallbackTweener] with a delay. A [Tween] can be created by using either [method SceneTree.create_tween] or [method Node.create_tween]. [Tween]s created manually (i.e. by using [code]Tween.new()[/code]) are invalid and can't be used for tweening values. A tween animation is created by adding [Tweener]s to the [Tween] object, using [method tween_property], [method tween_interval], [method tween_callback] or [method tween_method]: - [codeblock] + [codeblocks] + [gdscript] var tween = get_tree().create_tween() tween.tween_property($Sprite, "modulate", Color.red, 1) tween.tween_property($Sprite, "scale", Vector2(), 1) tween.tween_callback($Sprite.queue_free) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = GetTree().CreateTween(); + tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f); + tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f); + tween.TweenCallback(new Callable(GetNode("Sprite").QueueFree)); + [/csharp] + [/codeblocks] This sequence will make the [code]$Sprite[/code] node turn red, then shrink, before finally calling [method Node.queue_free] to free the sprite. [Tweener]s are executed one after another by default. This behavior can be changed using [method parallel] and [method set_parallel]. When a [Tweener] is created with one of the [code]tween_*[/code] methods, a chained method call can be used to tweak the properties of this [Tweener]. For example, if you want to set a different transition type in the above example, you can use [method set_trans]: - [codeblock] + [codeblocks] + [gdscript] var tween = get_tree().create_tween() tween.tween_property($Sprite, "modulate", Color.red, 1).set_trans(Tween.TRANS_SINE) tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE) tween.tween_callback($Sprite.queue_free) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = GetTree().CreateTween(); + tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f).SetTrans(Tween.TransitionType.Sine); + tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f).SetTrans(Tween.TransitionType.Bounce); + tween.TweenCallback(new Callable(GetNode("Sprite").QueueFree)); + [/csharp] + [/codeblocks] Most of the [Tween] methods can be chained this way too. In the following example the [Tween] is bound to the running script's node and a default transition is set for its [Tweener]s: - [codeblock] + [codeblocks] + [gdscript] var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC) tween.tween_property($Sprite, "modulate", Color.red, 1) tween.tween_property($Sprite, "scale", Vector2(), 1) tween.tween_callback($Sprite.queue_free) - [/codeblock] + [/gdscript] + [csharp] + var tween = GetTree().CreateTween().BindNode(this).SetTrans(Tween.TransitionType.Elastic); + tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f); + tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f); + tween.TweenCallback(new Callable(GetNode("Sprite").QueueFree)); + [/csharp] + [/codeblocks] Another interesting use for [Tween]s is animating arbitrary sets of objects: - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween() for sprite in get_children(): tween.tween_property(sprite, "position", Vector2(0, 0), 1) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween(); + foreach (Node sprite in GetChildren()) + tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f); + [/csharp] + [/codeblocks] In the example above, all children of a node are moved one after another to position (0, 0). You should avoid using more than one [Tween] per object's property. If two or more tweens animate one property at the same time, the last one created will take priority and assign the final value. If you want to interrupt and restart an animation, consider assigning the [Tween] to a variable: - [codeblock] + [codeblocks] + [gdscript] var tween func animate(): if tween: tween.kill() # Abort the previous animation. tween = create_tween() - [/codeblock] + [/gdscript] + [csharp] + private Tween tween; + + public void Animate() + { + if (tween != null) + tween.Kill(); // Abort the previous animation + tween = CreateTween(); + } + [/csharp] + [/codeblocks] Some [Tweener]s use transitions and eases. The first accepts a [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best. [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url] [b]Note:[/b] All [Tween]s will automatically start by default. To prevent a [Tween] from autostarting, you can call [method stop] immediately after it is created. @@ -64,12 +107,20 @@ <return type="Tween" /> <description> Used to chain two [Tweener]s after [method set_parallel] is called with [code]true[/code]. - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween().set_parallel(true) tween.tween_property(...) tween.tween_property(...) # Will run parallelly with above. tween.chain().tween_property(...) # Will run after two above are finished. - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween().SetParallel(true); + tween.TweenProperty(...); + tween.TweenProperty(...); // Will run parallelly with above. + tween.Chain().TweenProperty(...); // Will run after two above are finished. + [/csharp] + [/codeblocks] </description> </method> <method name="custom_step"> @@ -127,12 +178,20 @@ <return type="Tween" /> <description> Makes the next [Tweener] run parallelly to the previous one. Example: - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween() tween.tween_property(...) tween.parallel().tween_property(...) tween.parallel().tween_property(...) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween(); + tween.TweenProperty(...); + tween.Parallel().TweenProperty(...); + tween.Parallel().TweenProperty(...); + [/csharp] + [/codeblocks] All [Tweener]s in the example will run at the same time. You can make the [Tween] parallel by default by using [method set_parallel]. </description> @@ -214,16 +273,30 @@ <description> Creates and appends a [CallbackTweener]. This method can be used to call an arbitrary method in any object. Use [method Callable.bind] to bind additional arguments for the call. Example: object that keeps shooting every 1 second. - [codeblock] + [codeblocks] + [gdscript] var tween = get_tree().create_tween().set_loops() tween.tween_callback(shoot).set_delay(1) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = GetTree().CreateTween().SetLoops(); + tween.TweenCallback(new Callable(Shoot)).SetDelay(1.0f); + [/csharp] + [/codeblocks] Example: turning a sprite red and then blue, with 2 second delay. - [codeblock] + [codeblocks] + [gdscript] var tween = get_tree().create_tween() tween.tween_callback($Sprite.set_modulate.bind(Color.red)).set_delay(2) tween.tween_callback($Sprite.set_modulate.bind(Color.blue)).set_delay(2) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = GetTree().CreateTween(); + Sprite2D sprite = GetNode<Sprite2D>("Sprite"); + tween.TweenCallback(new Callable(() => sprite.Modulate = Colors.Red)).SetDelay(2.0f); + tween.TweenCallback(new Callable(() => sprite.Modulate = Colors.Blue)).SetDelay(2.0f); + [/csharp] + [/codeblocks] </description> </method> <method name="tween_interval"> @@ -232,13 +305,21 @@ <description> Creates and appends an [IntervalTweener]. This method can be used to create delays in the tween animation, as an alternative to using the delay in other [Tweener]s, or when there's no animation (in which case the [Tween] acts as a timer). [param time] is the length of the interval, in seconds. Example: creating an interval in code execution. - [codeblock] + [codeblocks] + [gdscript] # ... some code await create_tween().tween_interval(2).finished # ... more code - [/codeblock] + [/gdscript] + [csharp] + // ... some code + await ToSignal(CreateTween().TweenInterval(2.0f), Tween.SignalName.Finished); + // ... more code + [/csharp] + [/codeblocks] Example: creating an object that moves back and forth and jumps every few seconds. - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween().set_loops() tween.tween_property($Sprite, "position:x", 200.0, 1).as_relative() tween.tween_callback(jump) @@ -246,7 +327,17 @@ tween.tween_property($Sprite, "position:x", -200.0, 1).as_relative() tween.tween_callback(jump) tween.tween_interval(2) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween().SetLoops(); + tween.TweenProperty(GetNode("Sprite"), "position:x", 200.0f, 1.0f).AsRelative(); + tween.TweenCallback(new Callable(Jump)); + tween.TweenInterval(2.0f); + tween.TweenProperty(GetNode("Sprite"), "position:x", -200.0f, 1.0f).AsRelative(); + tween.TweenCallback(new Callable(Jump)); + tween.TweenInterval(2.0f); + [/csharp] + [/codeblocks] </description> </method> <method name="tween_method"> @@ -258,19 +349,41 @@ <description> Creates and appends a [MethodTweener]. This method is similar to a combination of [method tween_callback] and [method tween_property]. It calls a method over time with a tweened value provided as an argument. The value is tweened between [param from] and [param to] over the time specified by [param duration], in seconds. Use [method Callable.bind] to bind additional arguments for the call. You can use [method MethodTweener.set_ease] and [method MethodTweener.set_trans] to tweak the easing and transition of the value or [method MethodTweener.set_delay] to delay the tweening. Example: making a 3D object look from one point to another point. - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween() tween.tween_method(look_at.bind(Vector3.UP), Vector3(-1, 0, -1), Vector3(1, 0, -1), 1) # The look_at() method takes up vector as second argument. - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween(); + tween.TweenMethod(new Callable(() => LookAt(Vector3.Up)), new Vector3(-1.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, -1.0f), 1.0f); // The LookAt() method takes up vector as second argument. + [/csharp] + [/codeblocks] Example: setting a text of a [Label], using an intermediate method and after a delay. - [codeblock] + [codeblocks] + [gdscript] func _ready(): var tween = create_tween() tween.tween_method(set_label_text, 0, 10, 1).set_delay(1) func set_label_text(value: int): $Label.text = "Counting " + str(value) - [/codeblock] + [/gdscript] + [csharp] + public override void _Ready() + { + base._Ready(); + + Tween tween = CreateTween(); + tween.TweenMethod(new Callable(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f); + } + + private void SetLabelText(int value) + { + GetNode<Label>("Label").Text = $"Counting {value}"; + } + [/csharp] + [/codeblocks] </description> </method> <method name="tween_property"> @@ -281,19 +394,33 @@ <param index="3" name="duration" type="float" /> <description> Creates and appends a [PropertyTweener]. This method tweens a [param property] of an [param object] between an initial value and [param final_val] in a span of time equal to [param duration], in seconds. The initial value by default is the property's value at the time the tweening of the [PropertyTweener] starts. For example: - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween() tween.tween_property($Sprite, "position", Vector2(100, 200), 1) tween.tween_property($Sprite, "position", Vector2(200, 300), 1) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween(); + tween.TweenProperty(GetNode("Sprite"), "position", new Vector2(100.0f, 200.0f), 1.0f); + tween.TweenProperty(GetNode("Sprite"), "position", new Vector2(200.0f, 300.0f), 1.0f); + [/csharp] + [/codeblocks] will move the sprite to position (100, 200) and then to (200, 300). If you use [method PropertyTweener.from] or [method PropertyTweener.from_current], the starting position will be overwritten by the given value instead. See other methods in [PropertyTweener] to see how the tweening can be tweaked further. [b]Note:[/b] You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component. Example: moving object twice from the same position, with different transition types. - [codeblock] + [codeblocks] + [gdscript] var tween = create_tween() tween.tween_property($Sprite, "position", Vector2.RIGHT * 300, 1).as_relative().set_trans(Tween.TRANS_SINE) tween.tween_property($Sprite, "position", Vector2.RIGHT * 300, 1).as_relative().from_current().set_trans(Tween.TRANS_EXPO) - [/codeblock] + [/gdscript] + [csharp] + Tween tween = CreateTween(); + tween.TweenProperty(GetNode("Sprite"), "position", Vector2.Right * 300.0f, 1.0f).AsRelative().SetTrans(Tween.TransitionType.Sine); + tween.TweenProperty(GetNode("Sprite"), "position", Vector2.Right * 300.0f, 1.0f).AsRelative().FromCurrent().SetTrans(Tween.TransitionType.Expo); + [/csharp] + [/codeblocks] </description> </method> </methods> diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index 3ef59b1c39..7258efbdda 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -62,12 +62,11 @@ <tutorials> </tutorials> <methods> - <method name="add_do_method" qualifiers="vararg"> + <method name="add_do_method"> <return type="void" /> - <param index="0" name="object" type="Object" /> - <param index="1" name="method" type="StringName" /> + <param index="0" name="callable" type="Callable" /> <description> - Register a [param method] that will be called when the action is committed. + Register a [Callable] that will be called when the action is committed. </description> </method> <method name="add_do_property"> @@ -86,12 +85,11 @@ Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources. </description> </method> - <method name="add_undo_method" qualifiers="vararg"> + <method name="add_undo_method"> <return type="void" /> - <param index="0" name="object" type="Object" /> - <param index="1" name="method" type="StringName" /> + <param index="0" name="callable" type="Callable" /> <description> - Register a [param method] that will be called when the action is undone. + Register a [Callable] that will be called when the action is undone. </description> </method> <method name="add_undo_property"> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 8d4954136e..0ffede0992 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -198,7 +198,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ int item_count = 0; bool backbuffer_cleared = false; bool time_used = false; - bool material_screen_texture_found = false; + bool material_screen_texture_cached = false; + bool material_screen_texture_mipmaps_cached = false; Rect2 back_buffer_rect; bool backbuffer_copy = false; bool backbuffer_gen_mipmaps = false; @@ -223,10 +224,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ GLES3::CanvasMaterialData *md = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM)); if (md && md->shader_data->valid) { if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { - if (!material_screen_texture_found) { + if (!material_screen_texture_cached) { backbuffer_copy = true; back_buffer_rect = Rect2(); backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps; + } else if (!material_screen_texture_mipmaps_cached) { + backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps; } } @@ -287,7 +290,16 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps); backbuffer_copy = false; - material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies + backbuffer_gen_mipmaps = false; + material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies. + material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps; + } + + if (backbuffer_gen_mipmaps) { + texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect); + + backbuffer_gen_mipmaps = false; + material_screen_texture_mipmaps_cached = true; } // just add all items for now diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 1952efff0e..85b35639ec 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1719,7 +1719,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b glBindBuffer(GL_UNIFORM_BUFFER, 0); } -void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { +void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::Config *config = GLES3::Config::get_singleton(); RENDER_TIMESTAMP("Setup 3D Scene"); @@ -2481,7 +2481,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() { scene_globals.default_shader = material_storage->shader_allocate(); material_storage->shader_initialize(scene_globals.default_shader); material_storage->shader_set_code(scene_globals.default_shader, R"( -// Default 3D material shader (clustered). +// Default 3D material shader. shader_type spatial; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 881fc5615c..f0dc972678 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -124,7 +124,7 @@ struct RenderDataGLES3 { uint32_t spot_light_count = 0; uint32_t omni_light_count = 0; - RendererScene::RenderInfo *render_info = nullptr; + RenderingMethod::RenderInfo *render_info = nullptr; }; class RasterizerCanvasGLES3; @@ -304,12 +304,13 @@ private: }; enum { - INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5, - INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, - INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, - INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, - INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11, + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4, + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10, + INSTANCE_DATA_FLAG_PARTICLES = 1 << 11, INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, @@ -711,7 +712,7 @@ public: void voxel_gi_set_quality(RS::VoxelGIQuality) override; - void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; + void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override; diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index f054f0fdc6..8b708116ac 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -36,6 +36,7 @@ #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" +#include "drivers/gles3/storage/texture_storage.h" #include "servers/rendering/renderer_compositor.h" #include "servers/rendering/storage/light_storage.h" #include "servers/rendering/storage/utilities.h" @@ -246,7 +247,7 @@ public: const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); - return light_owner.owns(light->projector); + return TextureStorage::get_singleton()->owns_texture(light->projector); } _FORCE_INLINE_ bool light_is_negative(RID p_light) const { diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 8d2f8a7ed6..165de34c71 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -36,7 +36,7 @@ #include <string.h> -Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { const uint64_t buffer_size = f->get_length(); Vector<uint8_t> file_buffer; Error err = file_buffer.resize(buffer_size); diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index 91c3c8925f..a247d77310 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -40,7 +40,7 @@ private: static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size); public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderPNG(); }; diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index 504ef9843a..53a7f7aa4f 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -34,11 +34,11 @@ #include "drivers/png/image_loader_png.h" #include "drivers/png/resource_saver_png.h" -static ImageLoaderPNG *image_loader_png; +static Ref<ImageLoaderPNG> image_loader_png; static Ref<ResourceSaverPNG> resource_saver_png; void register_core_driver_types() { - image_loader_png = memnew(ImageLoaderPNG); + image_loader_png.instantiate(); ImageLoader::add_image_format_loader(image_loader_png); resource_saver_png.instantiate(); @@ -46,9 +46,8 @@ void register_core_driver_types() { } void unregister_core_driver_types() { - if (image_loader_png) { - memdelete(image_loader_png); - } + ImageLoader::remove_image_format_loader(image_loader_png); + image_loader_png.unref(); ResourceSaver::remove_resource_format_saver(resource_saver_png); resource_saver_png.unref(); diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 388ad479b9..300fbcdcfd 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -70,7 +70,7 @@ void FileAccessUnix::check_errors() const { } } -Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { +Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) { _close(); path_src = p_path; diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 297c34e454..e1311a80f8 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -54,7 +54,7 @@ class FileAccessUnix : public FileAccess { public: static CloseNotificationFunc close_notification_func; - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual String get_path() const override; /// returns the path for the current open file diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index beb2812999..ab298a0e49 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -194,6 +194,14 @@ String OS_Unix::get_name() const { return "Unix"; } +String OS_Unix::get_distribution_name() const { + return ""; +} + +String OS_Unix::get_version() const { + return ""; +} + double OS_Unix::get_unix_time() const { struct timeval tv_now; gettimeofday(&tv_now, nullptr); diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index b4c844bfef..8ef650f28b 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -62,6 +62,8 @@ public: virtual Error set_cwd(const String &p_cwd) override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual DateTime get_datetime(bool p_utc) const override; virtual TimeZoneInfo get_time_zone_info() const override; diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 73ae108961..53e9146f85 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -9367,10 +9367,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de // NOTE: If adding new project settings here, also duplicate their definition in // rendering_server.cpp for headless doctool. - staging_buffer_block_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256); + staging_buffer_block_size = GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256); staging_buffer_block_size = MAX(4u, staging_buffer_block_size); staging_buffer_block_size *= 1024; // Kb -> bytes. - staging_buffer_max_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128); + staging_buffer_max_size = GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128); staging_buffer_max_size = MAX(1u, staging_buffer_max_size); staging_buffer_max_size *= 1024 * 1024; @@ -9378,7 +9378,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de // Validate enough blocks. staging_buffer_max_size = staging_buffer_block_size * 4; } - texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); + texture_upload_region_size_px = GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64); texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px); frames_drawn = frame_count; // Start from frame count, so everything else is immediately old. @@ -9393,7 +9393,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de ERR_CONTINUE(err != OK); } - max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64); + max_descriptors_per_pool = GLOBAL_DEF("rendering/rendering_device/descriptor_pools/max_descriptors_per_pool", 64); // Check to make sure DescriptorPoolKey is good. static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t)); diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 1a66d19373..095d936c78 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -58,7 +58,7 @@ void FileAccessWindows::check_errors() const { } } -Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { +Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { _close(); path_src = p_path; diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 8629bb936b..d84c400775 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -51,7 +51,7 @@ class FileAccessWindows : public FileAccess { void _close(); public: - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 virtual String get_path() const override; /// returns the path for the current open file diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 219f3fdbe1..3b87b3e65e 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -667,8 +667,8 @@ void AnimationBezierTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) { void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) { editor = p_editor; - connect("clear_selection", Callable(editor, "_clear_selection").bind(false)); - connect("select_key", Callable(editor, "_key_selected"), CONNECT_DEFERRED); + connect("clear_selection", callable_mp(editor, &AnimationTrackEditor::_clear_selection).bind(false)); + connect("select_key", callable_mp(editor, &AnimationTrackEditor::_key_selected), CONNECT_DEFERRED); } void AnimationBezierTrackEdit::_play_position_draw() { diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 70b5501692..9529460ab1 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1445,7 +1445,9 @@ void AnimationTimelineEdit::_anim_loop_pressed() { default: break; } + undo_redo->add_do_method(this, "update_values"); undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode()); + undo_redo->add_undo_method(this, "update_values"); undo_redo->commit_action(); } else { String base_path = animation->get_path(); @@ -1913,6 +1915,8 @@ void AnimationTimelineEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only"))); ADD_SIGNAL(MethodInfo("track_added", PropertyInfo(Variant::INT, "track"))); ADD_SIGNAL(MethodInfo("length_changed", PropertyInfo(Variant::FLOAT, "size"))); + + ClassDB::bind_method(D_METHOD("update_values"), &AnimationTimelineEdit::update_values); } AnimationTimelineEdit::AnimationTimelineEdit() { @@ -3420,9 +3424,6 @@ void AnimationTrackEditGroup::_zoom_changed() { queue_redraw(); } -void AnimationTrackEditGroup::_bind_methods() { -} - AnimationTrackEditGroup::AnimationTrackEditGroup() { set_mouse_filter(MOUSE_FILTER_PASS); } @@ -6050,10 +6051,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { real_t to_diff = fmod(b - a, Math_TAU); to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff; } - Variant delta_v; - Variant::sub(to_v, from_v, delta_v); + Variant delta_v = Animation::subtract_variant(to_v, from_v); double duration = to_t - from_t; - double fixed_duration = duration - 0.01; // Prevent to overwrap keys... + double fixed_duration = duration - UNIT_EPSILON; // Prevent to overwrap keys... for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) { Pair<real_t, Variant> keydata; keydata.first = from_t + delta_t; @@ -6458,16 +6458,11 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() { } void AnimationTrackEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update); - ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus); - ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks); - ClassDB::bind_method(D_METHOD("_redraw_tracks"), &AnimationTrackEditor::_redraw_tracks); - ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim); - ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim); - - ClassDB::bind_method(D_METHOD("_key_selected"), &AnimationTrackEditor::_key_selected); // Still used by some connect_compat. - ClassDB::bind_method(D_METHOD("_key_deselected"), &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat. - ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat. + ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update); + ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus); + ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim); + ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim); + ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection); ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE)); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index ac69b88e99..5c51921d93 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -280,7 +280,6 @@ class AnimationTrackEditGroup : public Control { void _zoom_changed(); protected: - static void _bind_methods(); void _notification(int p_what); public: @@ -407,7 +406,6 @@ class AnimationTrackEditor : public VBoxContainer { void _insert_key_from_track(float p_ofs, int p_track); void _add_method_key(const String &p_method); - void _clear_selection(bool p_update = false); void _clear_selection_for_anim(const Ref<Animation> &p_anim); void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos); @@ -425,9 +423,6 @@ class AnimationTrackEditor : public VBoxContainer { RBMap<SelectedKey, KeyInfo> selection; - void _key_selected(int p_key, bool p_single, int p_track); - void _key_deselected(int p_key, int p_track); - bool moving_selection = false; float moving_selection_offset = 0.0f; void _move_selection_begin(); @@ -531,6 +526,11 @@ protected: void _notification(int p_what); public: + // Public for use with callable_mp. + void _clear_selection(bool p_update = false); + void _key_selected(int p_key, bool p_single, int p_track); + void _key_deselected(int p_key, int p_track); + enum { EDIT_COPY_TRACKS, EDIT_COPY_TRACKS_CONFIRM, diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 861d05f17a..236f3d7b08 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -238,6 +238,12 @@ void ConnectDialog::_notification(int p_what) { String type_name = Variant::get_type_name((Variant::Type)type_list->get_item_id(i)); type_list->set_item_icon(i, get_theme_icon(type_name, SNAME("EditorIcons"))); } + + 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); + from_signal->add_theme_style_override("normal", style); + } } break; } } @@ -465,30 +471,31 @@ ConnectDialog::ConnectDialog() { vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count); - HBoxContainer *dstm_hb = memnew(HBoxContainer); - vbc_left->add_margin_child(TTR("Receiver Method:"), dstm_hb); - dst_method = memnew(LineEdit); dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL); dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted)); - dstm_hb->add_child(dst_method); + vbc_left->add_margin_child(TTR("Receiver Method:"), dst_method); advanced = memnew(CheckButton); - dstm_hb->add_child(advanced); + vbc_left->add_child(advanced); advanced->set_text(TTR("Advanced")); + advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND); advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed)); + HBoxContainer *hbox = memnew(HBoxContainer); + vbc_right->add_child(hbox); + deferred = memnew(CheckBox); deferred->set_h_size_flags(0); deferred->set_text(TTR("Deferred")); deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time.")); - vbc_right->add_child(deferred); + hbox->add_child(deferred); one_shot = memnew(CheckBox); one_shot->set_h_size_flags(0); - one_shot->set_text(TTR("Oneshot")); + one_shot->set_text(TTR("One Shot")); one_shot->set_tooltip_text(TTR("Disconnects the signal after its first emission.")); - vbc_right->add_child(one_shot); + hbox->add_child(one_shot); cdbinds = memnew(ConnectDialogBinds); @@ -810,7 +817,7 @@ void ConnectionsDock::_go_to_script(TreeItem &p_item) { } if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, cd.method)) { - EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT); + EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT); } } diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index ba1f2fd6af..a0913265eb 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -130,7 +130,7 @@ void EditorCommandPalette::_update_command_search(const String &search_text) { ti->set_metadata(0, entries[i].key_name); ti->set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT); ti->set_text(1, shortcut_text); - Color c = Color(1, 1, 1, 0.5); + Color c = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5); ti->set_custom_color(1, c); } diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 6d11cb10ed..2e7302aaf9 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -202,7 +202,6 @@ private: void _select_drive(int p_idx); void _dir_submitted(String p_dir); - void _file_submitted(const String &p_file); void _action_pressed(); void _save_confirm_pressed(); void _cancel_pressed(); @@ -240,6 +239,9 @@ protected: static void _bind_methods(); public: + // Public for use with callable_mp. + void _file_submitted(const String &p_file); + void popup_file_dialog(); void clear_filters(); void add_filter(const String &p_filter, const String &p_description = ""); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 177bc6d2b2..b89bd23859 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -690,7 +690,6 @@ void EditorFileSystem::scan() { _update_extensions(); - abort_scan = false; if (!use_threads) { scanning = true; scan_total = 0; @@ -1162,8 +1161,6 @@ void EditorFileSystem::scan_changes() { scanning_changes = true; scanning_changes_done = false; - abort_scan = false; - if (!use_threads) { if (filesystem) { EditorProgressBG pr("sources", TTR("ScanSources"), 1000); @@ -1195,8 +1192,6 @@ void EditorFileSystem::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { Thread &active_thread = thread.is_started() ? thread : thread_sources; if (use_threads && active_thread.is_started()) { - //abort thread if in progress - abort_scan = true; while (scanning) { OS::get_singleton()->delay_usec(1000); } diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index f4e69b95e7..e06c6e4593 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -168,7 +168,6 @@ class EditorFileSystem : public Node { EditorFileSystemDirectory *new_filesystem = nullptr; - bool abort_scan = false; bool scanning = false; bool importing = false; bool first_scan = true; diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 7e7d7ca418..1b8146a0f0 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -324,11 +324,16 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() { } bool EditorHelpSearch::Runner::_phase_match_classes() { + if (!iterator_doc) { + return true; + } + DocData::ClassDoc &class_doc = iterator_doc->value; if (class_doc.name.is_empty()) { ++iterator_doc; return false; } + if (!_is_class_disabled_by_feature_profile(class_doc.name)) { ClassMatch match; match.doc = &class_doc; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 9e7314bf50..e786461722 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -426,6 +426,9 @@ void EditorProperty::_set_read_only(bool p_read_only) { void EditorProperty::set_read_only(bool p_read_only) { read_only = p_read_only; + if (GDVIRTUAL_CALL(_set_read_only, p_read_only)) { + return; + } _set_read_only(p_read_only); } @@ -458,7 +461,7 @@ StringName EditorProperty::_get_revert_property() const { return property; } -void EditorProperty::update_revert_and_pin_status() { +void EditorProperty::update_editor_property_status() { if (property == StringName()) { return; //no property, so nothing to do } @@ -469,15 +472,26 @@ void EditorProperty::update_revert_and_pin_status() { CRASH_COND(!node); new_pinned = node->is_property_pinned(property); } + Variant current = object->get(_get_revert_property()); bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, ¤t) && !is_read_only(); - if (new_can_revert != can_revert || new_pinned != pinned) { + bool new_checked = checked; + if (checkable) { // for properties like theme overrides. + bool valid = false; + Variant value = object->get(property, &valid); + if (valid) { + new_checked = value.get_type() != Variant::NIL; + } + } + + if (new_can_revert != can_revert || new_pinned != pinned || new_checked != checked) { if (new_can_revert != can_revert) { emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert); } can_revert = new_can_revert; pinned = new_pinned; + checked = new_checked; queue_redraw(); } } @@ -974,7 +988,9 @@ void EditorProperty::_bind_methods() { ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx"))); GDVIRTUAL_BIND(_update_property) - ClassDB::bind_method(D_METHOD("_update_revert_and_pin_status"), &EditorProperty::update_revert_and_pin_status); + GDVIRTUAL_BIND(_set_read_only, "read_only") + + ClassDB::bind_method(D_METHOD("_update_editor_property_status"), &EditorProperty::update_editor_property_status); } EditorProperty::EditorProperty() { @@ -2552,7 +2568,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn ep->set_read_only(read_only); ep->update_property(); ep->_update_pin_flags(); - ep->update_revert_and_pin_status(); + ep->update_editor_property_status(); ep->set_deletable(deletable_properties); ep->update_cache(); } @@ -3038,7 +3054,7 @@ void EditorInspector::update_tree() { bool movable = true; bool numbered = false; bool foldable = use_folding; - String add_button_text; + String add_button_text = TTR("Add Element"); String swap_method; for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) { if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) { @@ -3211,6 +3227,7 @@ void EditorInspector::update_tree() { // Use the existing one. ep->set_label(property_label_string); } + for (int j = 0; j < properties.size(); j++) { String prop = properties[j]; @@ -3258,7 +3275,7 @@ void EditorInspector::update_tree() { ep->set_doc_path(doc_info.path); ep->update_property(); ep->_update_pin_flags(); - ep->update_revert_and_pin_status(); + ep->update_editor_property_status(); ep->update_cache(); if (current_selected && ep->property == current_selected) { @@ -3297,7 +3314,7 @@ void EditorInspector::update_property(const String &p_prop) { for (EditorProperty *E : editor_property_map[p_prop]) { E->update_property(); - E->update_revert_and_pin_status(); + E->update_editor_property_status(); E->update_cache(); } } @@ -3640,7 +3657,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo if (editor_property_map.has(p_name)) { for (EditorProperty *E : editor_property_map[p_name]) { - E->update_revert_and_pin_status(); + E->update_editor_property_status(); } } } @@ -3754,7 +3771,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) { for (EditorProperty *E : editor_property_map[p_path]) { E->set_checked(p_checked); E->update_property(); - E->update_revert_and_pin_status(); + E->update_editor_property_status(); E->update_cache(); } } @@ -3778,8 +3795,8 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) { undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned); if (editor_property_map.has(p_path)) { for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { - undo_redo->add_do_method(E->get(), "_update_revert_and_pin_status"); - undo_redo->add_undo_method(E->get(), "_update_revert_and_pin_status"); + undo_redo->add_do_method(E->get(), "_update_editor_property_status"); + undo_redo->add_undo_method(E->get(), "_update_editor_property_status"); } } undo_redo->commit_action(); @@ -3787,7 +3804,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) { node->set_property_pinned(p_path, p_pinned); if (editor_property_map.has(p_path)) { for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { - E->get()->update_revert_and_pin_status(); + E->get()->update_editor_property_status(); } } } @@ -3868,7 +3885,7 @@ void EditorInspector::_notification(int p_what) { for (EditorProperty *E : F.value) { if (E && !E->is_cache_valid()) { E->update_property(); - E->update_revert_and_pin_status(); + E->update_editor_property_status(); E->update_cache(); } } @@ -3890,7 +3907,7 @@ void EditorInspector::_notification(int p_what) { if (editor_property_map.has(prop)) { for (EditorProperty *E : editor_property_map[prop]) { E->update_property(); - E->update_revert_and_pin_status(); + E->update_editor_property_status(); E->update_cache(); } } @@ -3983,13 +4000,7 @@ void EditorInspector::_check_meta_name(const String &p_name) { } else if (!p_name.is_valid_identifier()) { error = TTR("Metadata name must be a valid identifier."); } else if (object->has_meta(p_name)) { - Node *node = Object::cast_to<Node>(object); - if (node) { - error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name()); - } else { - // This should normally never be reached, but the error is set just in case. - error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name()); - } + error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name); } else if (p_name[0] == '_') { error = TTR("Names starting with _ are reserved for editor-only metadata."); } @@ -4009,14 +4020,6 @@ void EditorInspector::_show_add_meta_dialog() { if (!add_meta_dialog) { add_meta_dialog = memnew(ConfirmationDialog); - Node *node = Object::cast_to<Node>(object); - if (node) { - add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name())); - } else { - // This should normally never be reached, but the title is set just in case. - add_meta_dialog->set_title(vformat(TTR("Add Metadata Property"), node->get_name())); - } - VBoxContainer *vbc = memnew(VBoxContainer); add_meta_dialog->add_child(vbc); HBoxContainer *hbc = memnew(HBoxContainer); @@ -4046,6 +4049,14 @@ void EditorInspector::_show_add_meta_dialog() { add_meta_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name)); } + Node *node = Object::cast_to<Node>(object); + if (node) { + add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name())); + } else { + // This should normally be reached when the object is derived from Resource. + add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), object->get_class())); + } + add_meta_dialog->popup_centered(); add_meta_name->set_text(""); _check_meta_name(""); @@ -4054,6 +4065,7 @@ void EditorInspector::_show_add_meta_dialog() { void EditorInspector::_bind_methods() { ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change); + ClassDB::bind_method("get_selected_path", &EditorInspector::get_selected_path); ADD_SIGNAL(MethodInfo("property_selected", PropertyInfo(Variant::STRING, "property"))); ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "advance"))); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 70378d8cf2..872007e637 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -120,6 +120,8 @@ private: HashMap<StringName, Variant> cache; GDVIRTUAL0(_update_property) + GDVIRTUAL1(_set_read_only, bool) + void _update_pin_flags(); protected: @@ -151,7 +153,7 @@ public: void set_doc_path(const String &p_doc_path); virtual void update_property(); - void update_revert_and_pin_status(); + void update_editor_property_status(); virtual bool use_keying_next() const; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8eaddcb7e1..9ac6fd66ef 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -465,15 +465,15 @@ void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) { } if (ED_IS_SHORTCUT("editor/editor_2d", p_event)) { - _editor_select(EDITOR_2D); + editor_select(EDITOR_2D); } else if (ED_IS_SHORTCUT("editor/editor_3d", p_event)) { - _editor_select(EDITOR_3D); + editor_select(EDITOR_3D); } else if (ED_IS_SHORTCUT("editor/editor_script", p_event)) { - _editor_select(EDITOR_SCRIPT); + editor_select(EDITOR_SCRIPT); } else if (ED_IS_SHORTCUT("editor/editor_help", p_event)) { emit_signal(SNAME("request_help_search"), ""); } else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && AssetLibraryEditorPlugin::is_available()) { - _editor_select(EDITOR_ASSETLIB); + editor_select(EDITOR_ASSETLIB); } else if (ED_IS_SHORTCUT("editor/editor_next", p_event)) { _editor_select_next(); } else if (ED_IS_SHORTCUT("editor/editor_prev", p_event)) { @@ -584,7 +584,7 @@ void EditorNode::_update_from_settings() { void EditorNode::_select_default_main_screen_plugin() { if (EDITOR_3D < main_editor_buttons.size() && main_editor_buttons[EDITOR_3D]->is_visible()) { // If the 3D editor is enabled, use this as the default. - _editor_select(EDITOR_3D); + editor_select(EDITOR_3D); return; } @@ -593,12 +593,12 @@ void EditorNode::_select_default_main_screen_plugin() { for (int i = 0; i < main_editor_buttons.size(); i++) { Button *editor_button = main_editor_buttons[i]; if (editor_button->is_visible()) { - _editor_select(i); + editor_select(i); return; } } - _editor_select(-1); + editor_select(-1); } void EditorNode::_notification(int p_what) { @@ -1190,7 +1190,7 @@ void EditorNode::_editor_select_next() { } } while (!main_editor_buttons[editor]->is_visible()); - _editor_select(editor); + editor_select(editor); } void EditorNode::_open_command_palette() { @@ -1208,7 +1208,7 @@ void EditorNode::_editor_select_prev() { } } while (!main_editor_buttons[editor]->is_visible()); - _editor_select(editor); + editor_select(editor); } Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_deps) { @@ -2390,7 +2390,7 @@ 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())) { // Update screen main_plugin. - _editor_select(plugin_index); + editor_select(plugin_index); main_plugin->edit(current_obj); } else { editor_plugin_screen->edit(current_obj); @@ -2450,7 +2450,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file"); } if (write_movie_file == String()) { - show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the 'Editor/Movie Writer' category.\nAlternatively, for running single scenes, a 'movie_path' metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK")); + show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the Editor > Movie Writer category.\nAlternatively, for running single scenes, a `movie_file` string metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK")); return; } } @@ -2763,18 +2763,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } else if (extensions.size()) { String root_name = scene->get_name(); - // Very similar to node naming logic. - switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) { - case SCENE_NAME_CASING_AUTO: - // Use casing of the root node. - break; - case SCENE_NAME_CASING_PASCAL_CASE: { - root_name = root_name.to_pascal_case(); - } break; - case SCENE_NAME_CASING_SNAKE_CASE: - root_name = root_name.replace("-", "_").to_snake_case(); - break; - } + root_name = EditorNode::adjust_scene_name_casing(root_name); file->set_current_path(root_name + "." + extensions.front()->get().to_lower()); } file->popup_file_dialog(); @@ -3080,8 +3069,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case HELP_SUPPORT_GODOT_DEVELOPMENT: { OS::get_singleton()->shell_open("https://godotengine.org/donate"); } break; - case SET_RENDERING_DRIVER_SAVE_AND_RESTART: { - ProjectSettings::get_singleton()->set("rendering/driver/driver_name", rendering_driver_request); + case SET_RENDERER_NAME_SAVE_AND_RESTART: { + ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method", renderer_request); ProjectSettings::get_singleton()->save(); save_all_scenes(); @@ -3090,6 +3079,19 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } +String EditorNode::adjust_scene_name_casing(const String &root_name) { + switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) { + case SCENE_NAME_CASING_AUTO: + // Use casing of the root node. + break; + case SCENE_NAME_CASING_PASCAL_CASE: + return root_name.to_pascal_case(); + case SCENE_NAME_CASING_SNAKE_CASE: + return root_name.replace("-", "_").to_snake_case(); + } + return root_name; +} + void EditorNode::_request_screenshot() { _screenshot(); } @@ -3303,7 +3305,7 @@ VBoxContainer *EditorNode::get_main_screen_control() { return main_screen_vbox; } -void EditorNode::_editor_select(int p_which) { +void EditorNode::editor_select(int p_which) { static bool selecting = false; if (selecting || changing_scene) { return; @@ -3357,7 +3359,7 @@ void EditorNode::select_editor_by_name(const String &p_name) { for (int i = 0; i < main_editor_buttons.size(); i++) { if (main_editor_buttons[i]->get_text() == p_name) { - _editor_select(i); + editor_select(i); return; } } @@ -3370,7 +3372,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed Button *tb = memnew(Button); tb->set_flat(true); tb->set_toggle_mode(true); - tb->connect("pressed", callable_mp(singleton, &EditorNode::_editor_select).bind(singleton->main_editor_buttons.size())); + tb->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(singleton->main_editor_buttons.size())); tb->set_name(p_editor->get_name()); tb->set_text(p_editor->get_name()); @@ -3404,7 +3406,7 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan for (int i = 0; i < singleton->main_editor_buttons.size(); i++) { if (p_editor->get_name() == singleton->main_editor_buttons[i]->get_text()) { if (singleton->main_editor_buttons[i]->is_pressed()) { - singleton->_editor_select(EDITOR_SCRIPT); + singleton->editor_select(EDITOR_SCRIPT); } memdelete(singleton->main_editor_buttons[i]); @@ -3628,7 +3630,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { int index = p_state["editor_index"]; if (current < 2) { // If currently in spatial/2d, only switch to spatial/2d. If currently in script, stay there. if (index < 2 || !get_edited_scene()) { - _editor_select(index); + editor_select(index); } } } @@ -3639,9 +3641,9 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { int n2d = 0, n3d = 0; _find_node_types(get_edited_scene(), n2d, n3d); if (n2d > n3d) { - _editor_select(EDITOR_2D); + editor_select(EDITOR_2D); } else if (n3d > n2d) { - _editor_select(EDITOR_3D); + editor_select(EDITOR_3D); } } } @@ -3668,10 +3670,6 @@ bool EditorNode::is_changing_scene() const { return changing_scene; } -void EditorNode::_clear_undo_history() { - get_undo_redo()->clear_history(false); -} - void EditorNode::set_current_scene(int p_idx) { // Save the folding in case the scene gets reloaded. if (editor_data.get_scene_path(p_idx) != "" && editor_data.get_edited_scene_root(p_idx)) { @@ -5882,27 +5880,27 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) { top_split->set_visible(!p_pressed); } -void EditorNode::_update_rendering_driver_color() { - if (rendering_driver->get_text() == "opengl3") { - rendering_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff)); - } else if (rendering_driver->get_text() == "vulkan") { - rendering_driver->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor"))); +void EditorNode::_update_renderer_color() { + if (renderer->get_text() == "gl_compatibility") { + renderer->add_theme_color_override("font_color", Color::hex(0x5586a4ff)); + } else if (renderer->get_text() == "forward_plus" || renderer->get_text() == "mobile") { + renderer->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor"))); } } -void EditorNode::_rendering_driver_selected(int p_which) { - String driver = rendering_driver->get_item_metadata(p_which); +void EditorNode::_renderer_selected(int p_which) { + String rendering_method = renderer->get_item_metadata(p_which); - String current_driver = OS::get_singleton()->get_current_rendering_driver_name(); + String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method"); - if (driver == current_driver) { + if (rendering_method == current_renderer) { return; } - rendering_driver_request = driver; + renderer_request = rendering_method; video_restart_dialog->popup_centered(); - rendering_driver->select(rendering_driver_current); - _update_rendering_driver_color(); + renderer->select(renderer_current); + _update_renderer_color(); } void EditorNode::_resource_saved(Ref<Resource> p_resource, const String &p_path) { @@ -5937,7 +5935,7 @@ void EditorNode::_feature_profile_changed() { if ((profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D) && singleton->main_editor_buttons[EDITOR_3D]->is_pressed()) || (profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT) && singleton->main_editor_buttons[EDITOR_SCRIPT]->is_pressed()) || (AssetLibraryEditorPlugin::is_available() && profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB) && singleton->main_editor_buttons[EDITOR_ASSETLIB]->is_pressed())) { - _editor_select(EDITOR_2D); + editor_select(EDITOR_2D); } } else { import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false); @@ -5960,19 +5958,14 @@ void EditorNode::_bind_methods() { GLOBAL_DEF("editor/scene/scene_naming", SCENE_NAME_CASING_SNAKE_CASE); ProjectSettings::get_singleton()->set_custom_property_info("editor/scene/scene_naming", PropertyInfo(Variant::INT, "editor/scene/scene_naming", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case")); ClassDB::bind_method("edit_current", &EditorNode::edit_current); - ClassDB::bind_method("_editor_select", &EditorNode::_editor_select); - ClassDB::bind_method("_node_renamed", &EditorNode::_node_renamed); ClassDB::bind_method("edit_node", &EditorNode::edit_node); ClassDB::bind_method(D_METHOD("push_item", "object", "property", "inspector_only"), &EditorNode::push_item, DEFVAL(""), DEFVAL(false)); - ClassDB::bind_method("_get_scene_metadata", &EditorNode::_get_scene_metadata); ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene); ClassDB::bind_method("open_request", &EditorNode::open_request); ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource); ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only); - ClassDB::bind_method("_close_messages", &EditorNode::_close_messages); - ClassDB::bind_method("_show_messages", &EditorNode::_show_messages); ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process); @@ -5981,19 +5974,10 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state); ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes); - ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history); - ClassDB::bind_method("edit_item_resource", &EditorNode::edit_item_resource); ClassDB::bind_method(D_METHOD("get_gui_base"), &EditorNode::get_gui_base); - ClassDB::bind_method(D_METHOD("_on_plugin_ready"), &EditorNode::_on_plugin_ready); // Still used by some connect_compat. - - ClassDB::bind_method("_screenshot", &EditorNode::_screenshot); - ClassDB::bind_method("_save_screenshot", &EditorNode::_save_screenshot); - - ClassDB::bind_method("_version_button_pressed", &EditorNode::_version_button_pressed); - ADD_SIGNAL(MethodInfo("play_pressed")); ADD_SIGNAL(MethodInfo("pause_pressed")); ADD_SIGNAL(MethodInfo("stop_pressed")); @@ -6966,19 +6950,17 @@ EditorNode::EditorNode() { HBoxContainer *right_menu_hb = memnew(HBoxContainer); menu_hb->add_child(right_menu_hb); - rendering_driver = memnew(OptionButton); - + renderer = memnew(OptionButton); // Hide the renderer selection dropdown until OpenGL support is more mature. // The renderer can still be changed in the project settings or using `--rendering-driver opengl3`. - rendering_driver->set_visible(false); + renderer->set_visible(false); + renderer->set_flat(true); + renderer->set_focus_mode(Control::FOCUS_NONE); + renderer->connect("item_selected", callable_mp(this, &EditorNode::_renderer_selected)); + renderer->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts"))); + renderer->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"))); - rendering_driver->set_flat(true); - rendering_driver->set_focus_mode(Control::FOCUS_NONE); - rendering_driver->connect("item_selected", callable_mp(this, &EditorNode::_rendering_driver_selected)); - rendering_driver->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts"))); - rendering_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"))); - - right_menu_hb->add_child(rendering_driver); + right_menu_hb->add_child(renderer); if (can_expand) { // Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side). @@ -6988,36 +6970,35 @@ EditorNode::EditorNode() { menu_hb->add_child(menu_spacer); } - // Only display the render drivers that are available for this display driver. - int display_driver_idx = OS::get_singleton()->get_display_driver_id(); - Vector<String> render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx); - String current_rendering_driver = OS::get_singleton()->get_current_rendering_driver_name(); + String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method"); + + PackedStringArray renderers = ProjectSettings::get_singleton()->get_custom_property_info().get(StringName("rendering/renderer/rendering_method")).hint_string.split(",", false); // As we are doing string comparisons, keep in standard case to prevent problems with capitals // "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI. - current_rendering_driver = current_rendering_driver.to_lower(); + current_renderer = current_renderer.to_lower(); - for (int i = 0; i < render_drivers.size(); i++) { - String driver = render_drivers[i]; + for (int i = 0; i < renderers.size(); i++) { + String rendering_method = renderers[i]; - // Add the driver to the UI. - rendering_driver->add_item(driver); - rendering_driver->set_item_metadata(i, driver); + // Add the renderers name to the UI. + renderer->add_item(rendering_method); + renderer->set_item_metadata(i, rendering_method); // Lowercase for standard comparison. - driver = driver.to_lower(); + rendering_method = rendering_method.to_lower(); - if (current_rendering_driver == driver) { - rendering_driver->select(i); - rendering_driver_current = i; + if (current_renderer == rendering_method) { + renderer->select(i); + renderer_current = i; } } - _update_rendering_driver_color(); + _update_renderer_color(); video_restart_dialog = memnew(ConfirmationDialog); - video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor.")); + video_restart_dialog->set_text(TTR("Changing the renderer requires restarting the editor.")); video_restart_dialog->set_ok_button_text(TTR("Save & Restart")); - video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERING_DRIVER_SAVE_AND_RESTART)); + video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERER_NAME_SAVE_AND_RESTART)); gui_base->add_child(video_restart_dialog); progress_hb = memnew(BackgroundProgress); @@ -7547,6 +7528,7 @@ EditorNode::EditorNode() { // Extend menu bar to window title. if (can_expand) { + DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(menu_hb->get_minimum_size().y / 2, menu_hb->get_minimum_size().y / 2), DisplayServer::MAIN_WINDOW_ID); DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID); menu_hb->set_can_move_window(true); } diff --git a/editor/editor_node.h b/editor/editor_node.h index 200d68908c..14dab11358 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -125,6 +125,12 @@ public: EDITOR_ASSETLIB }; + enum SceneNameCasing { + SCENE_NAME_CASING_AUTO, + SCENE_NAME_CASING_PASCAL_CASE, + SCENE_NAME_CASING_SNAKE_CASE + }; + struct ExecuteThreadArgs { String path; List<String> args; @@ -218,7 +224,7 @@ private: HELP_ABOUT, HELP_SUPPORT_GODOT_DEVELOPMENT, - SET_RENDERING_DRIVER_SAVE_AND_RESTART, + SET_RENDERER_NAME_SAVE_AND_RESTART, GLOBAL_NEW_WINDOW, GLOBAL_SCENE, @@ -233,12 +239,6 @@ private: MAX_BUILD_CALLBACKS = 128 }; - enum ScriptNameCasing { - SCENE_NAME_CASING_AUTO, - SCENE_NAME_CASING_PASCAL_CASE, - SCENE_NAME_CASING_SNAKE_CASE - }; - struct BottomPanelItem { String name; Control *control = nullptr; @@ -286,12 +286,12 @@ private: Control *theme_base = nullptr; Control *gui_base = nullptr; VBoxContainer *main_vbox = nullptr; - OptionButton *rendering_driver = nullptr; + OptionButton *renderer = nullptr; ConfirmationDialog *video_restart_dialog = nullptr; - int rendering_driver_current = 0; - String rendering_driver_request; + int renderer_current = 0; + String renderer_request; // Split containers. HSplitContainer *left_l_hsplit = nullptr; @@ -543,7 +543,6 @@ private: void _update_file_menu_opened(); void _update_file_menu_closed(); - void _on_plugin_ready(Object *p_script, const String &p_activate_name); void _remove_plugin_from_enabled(const String &p_name); void _fs_changed(); @@ -553,7 +552,6 @@ private: void _node_renamed(); void _editor_select_next(); void _editor_select_prev(); - void _editor_select(int p_which); void _set_scene_metadata(const String &p_file, int p_idx = -1); void _get_scene_metadata(const String &p_file); void _update_title(); @@ -599,8 +597,8 @@ private: void _update_from_settings(); - void _rendering_driver_selected(int); - void _update_rendering_driver_color(); + void _renderer_selected(int); + void _update_renderer_color(); void _exit_editor(int p_exit_code); @@ -658,8 +656,6 @@ private: void _update_layouts_menu(); void _layout_menu_option(int p_id); - void _clear_undo_history(); - void _update_addon_config(); void _toggle_distraction_free_mode(); @@ -703,7 +699,11 @@ protected: void set_current_tab(int p_tab); public: - void set_visible_editor(EditorTable p_table) { _editor_select(p_table); } + // Public for use with callable_mp. + void _on_plugin_ready(Object *p_script, const String &p_activate_name); + + void editor_select(int p_which); + void set_visible_editor(EditorTable p_table) { editor_select(p_table); } bool call_build(); @@ -720,6 +720,8 @@ public: static HBoxContainer *get_menu_hb() { return singleton->menu_hb; } static VSplitContainer *get_top_split() { return singleton->top_split; } + static String adjust_scene_name_casing(const String &root_name); + static bool has_unsaved_changes() { return singleton->unsaved_cache; } static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames); static void add_io_error(const String &p_error); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index a8df486381..bd19df41fe 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -46,7 +46,7 @@ void EditorPluginSettings::_notification(int p_what) { } break; case Node::NOTIFICATION_READY: { - plugin_config_dialog->connect("plugin_ready", Callable(EditorNode::get_singleton(), "_on_plugin_ready")); + plugin_config_dialog->connect("plugin_ready", callable_mp(EditorNode::get_singleton(), &EditorNode::_on_plugin_ready)); plugin_list->connect("button_clicked", callable_mp(this, &EditorPluginSettings::_cell_button_pressed)); } break; } diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 7364258a07..3b99962435 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1758,7 +1758,7 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) { Vector2 v2; v2.x = spin[0]->get_value(); v2.y = spin[1]->get_value(); - emit_changed(get_edited_property(), v2, p_name); + emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name); } void EditorPropertyVector2::update_property() { @@ -2005,7 +2005,7 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) { v3.y = Math::deg_to_rad(v3.y); v3.z = Math::deg_to_rad(v3.z); } - emit_changed(get_edited_property(), v3, p_name); + emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name); } void EditorPropertyVector3::update_property() { @@ -2171,7 +2171,7 @@ void EditorPropertyVector2i::_value_changed(double val, const String &p_name) { Vector2i v2; v2.x = spin[0]->get_value(); v2.y = spin[1]->get_value(); - emit_changed(get_edited_property(), v2, p_name); + emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name); } void EditorPropertyVector2i::update_property() { @@ -2413,7 +2413,7 @@ void EditorPropertyVector3i::_value_changed(double val, const String &p_name) { v3.x = spin[0]->get_value(); v3.y = spin[1]->get_value(); v3.z = spin[2]->get_value(); - emit_changed(get_edited_property(), v3, p_name); + emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name); } void EditorPropertyVector3i::update_property() { diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp index 539cb7cd8a..b4ec3bca15 100644 --- a/editor/editor_quick_open.cpp +++ b/editor/editor_quick_open.cpp @@ -31,6 +31,7 @@ #include "editor_quick_open.h" #include "core/os/keyboard.h" +#include "editor/editor_node.h" void EditorQuickOpen::popup_dialog(const StringName &p_base, bool p_enable_multi, bool p_dontclear) { base_type = p_base; @@ -57,17 +58,29 @@ void EditorQuickOpen::_build_search_cache(EditorFileSystemDirectory *p_efsd) { Vector<String> base_types = String(base_type).split(String(",")); for (int i = 0; i < p_efsd->get_file_count(); i++) { - String file_type = p_efsd->get_file_type(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 actual_type = script_type.is_empty() ? engine_type : script_type; // Iterate all possible base types. for (String &parent_type : base_types) { - if (ClassDB::is_parent_class(file_type, parent_type)) { - String file = p_efsd->get_file_path(i); + if (ClassDB::is_parent_class(engine_type, parent_type) || EditorNode::get_editor_data().script_class_is_parent(script_type, parent_type)) { files.push_back(file.substr(6, file.length())); // Store refs to used icons. String ext = file.get_extension(); if (!icons.has(ext)) { - icons.insert(ext, get_theme_icon((has_theme_icon(file_type, SNAME("EditorIcons")) ? file_type : String("Object")), SNAME("EditorIcons"))); + icons.insert(ext, get_theme_icon((has_theme_icon(actual_type, SNAME("EditorIcons")) ? actual_type : String("Object")), SNAME("EditorIcons"))); } // Stop testing base types as soon as we got a match. diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h index e41a8c7e75..86a419b538 100644 --- a/editor/editor_quick_open.h +++ b/editor/editor_quick_open.h @@ -43,6 +43,7 @@ class EditorQuickOpen : public ConfirmationDialog { Tree *search_options = nullptr; StringName base_type; bool allow_multi_select = false; + bool _load_resources = true; Vector<String> files; OAHashMap<String, Ref<Texture2D>> icons; diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 84cb085551..de8259c25c 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -53,6 +53,7 @@ void EditorResourcePicker::_update_resource() { if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) { resource_path = edited_resource->get_path() + "\n"; } + String class_name = _get_resource_type(edited_resource); if (preview_rect) { preview_rect->set_texture(Ref<Texture2D>()); @@ -64,16 +65,20 @@ void EditorResourcePicker::_update_resource() { assign_button->set_text(TTR("<empty>")); assign_button->set_tooltip_text(""); } else { - assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object")); + assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), SNAME("Object"))); if (!edited_resource->get_name().is_empty()) { assign_button->set_text(edited_resource->get_name()); } else if (edited_resource->get_path().is_resource_file()) { assign_button->set_text(edited_resource->get_path().get_file()); } else { - assign_button->set_text(edited_resource->get_class()); + assign_button->set_text(class_name); } - assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class()); + + if (edited_resource->get_path().is_resource_file()) { + resource_path = edited_resource->get_path() + "\n"; + } + assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + class_name); // Preview will override the above, so called at the end. EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id()); @@ -134,16 +139,29 @@ void EditorResourcePicker::_file_selected(const String &p_path) { if (!base_type.is_empty()) { bool any_type_matches = false; + String res_type = loaded_resource->get_class(); + Ref<Script> res_script = loaded_resource->get_script(); + bool is_global_class = false; + if (res_script.is_valid()) { + String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path()); + if (!script_type.is_empty()) { + is_global_class = true; + res_type = script_type; + } + } + for (int i = 0; i < base_type.get_slice_count(","); i++) { String base = base_type.get_slice(",", i); - if (loaded_resource->is_class(base)) { - any_type_matches = true; + + any_type_matches = is_global_class ? EditorNode::get_editor_data().script_class_is_parent(res_type, base) : loaded_resource->is_class(base); + + if (!any_type_matches) { break; } } if (!any_type_matches) { - EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), loaded_resource->get_class(), base_type)); + EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), res_type, base_type)); return; } } @@ -227,16 +245,19 @@ void EditorResourcePicker::_update_menu_items() { // Add options to copy/paste resource. Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard(); bool paste_valid = false; - if (is_editable()) { - if (cb.is_valid()) { - if (base_type.is_empty()) { - paste_valid = true; - } else { - for (int i = 0; i < base_type.get_slice_count(","); i++) { - if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) { - paste_valid = true; - break; - } + if (is_editable() && cb.is_valid()) { + if (base_type.is_empty()) { + paste_valid = true; + } else { + String res_type = _get_resource_type(cb); + + for (int i = 0; i < base_type.get_slice_count(","); i++) { + String base = base_type.get_slice(",", i); + + paste_valid = ClassDB::is_parent_class(res_type, base) || EditorNode::get_editor_data().script_class_is_parent(res_type, base); + + if (!paste_valid) { + break; } } } @@ -281,6 +302,9 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { for (int i = 0; i < base_type.get_slice_count(","); i++) { String base = base_type.get_slice(",", i); ResourceLoader::get_recognized_extensions_for_type(base, &extensions); + if (ScriptServer::is_global_class(base)) { + ResourceLoader::get_recognized_extensions_for_type(ScriptServer::get_global_class_native_base(base), &extensions); + } } HashSet<String> valid_extensions; @@ -408,13 +432,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { Variant obj; if (ScriptServer::is_global_class(intype)) { - obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(intype)); - if (obj) { - Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype)); - if (script.is_valid()) { - ((Object *)obj)->set_script(script); - } - } + obj = EditorNode::get_editor_data().script_class_instance(intype); } else { obj = ClassDB::instantiate(intype); } @@ -512,23 +530,40 @@ void EditorResourcePicker::_button_draw() { void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { - // Only attempt to update and show the menu if we have - // a valid resource or the Picker is editable, as - // there will otherwise be nothing to display. - if (edited_resource.is_valid() || is_editable()) { - _update_menu_items(); - - Vector2 pos = get_screen_position() + mb->get_position(); - edit_menu->reset_size(); - edit_menu->set_position(pos); - edit_menu->popup(); - } + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { + // Only attempt to update and show the menu if we have + // a valid resource or the Picker is editable, as + // there will otherwise be nothing to display. + if (edited_resource.is_valid() || is_editable()) { + _update_menu_items(); + + Vector2 pos = get_screen_position() + mb->get_position(); + edit_menu->reset_size(); + edit_menu->set_position(pos); + edit_menu->popup(); } } } +String EditorResourcePicker::_get_resource_type(const Ref<Resource> &p_resource) const { + if (p_resource.is_null()) { + return String(); + } + String res_type = p_resource->get_class(); + + Ref<Script> res_script = p_resource->get_script(); + if (res_script.is_null()) { + return res_type; + } + + // TODO: Replace with EditorFileSystem when PR #60606 is merged to use cached resource type. + String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path()); + if (!script_type.is_empty()) { + res_type = script_type; + } + 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(); @@ -550,7 +585,9 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin List<StringName> allowed_subtypes; List<StringName> inheriters; - ClassDB::get_inheriters_from_class(base, &inheriters); + if (!ScriptServer::is_global_class(base)) { + ClassDB::get_inheriters_from_class(base, &inheriters); + } for (const StringName &subtype_name : inheriters) { p_vector->insert(subtype_name); allowed_subtypes.push_back(subtype_name); @@ -602,32 +639,29 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { } } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") { res = drag_data["resource"]; + } else if (drag_data.has("type") && String(drag_data["type"]) == "files") { + Vector<String> files = drag_data["files"]; + + // TODO: Extract the typename of the dropped filepath's resource in a more performant way, without fully loading it. + if (files.size() == 1) { + String file = files[0]; + res = ResourceLoader::load(file); + } } HashSet<String> allowed_types; _get_allowed_types(true, &allowed_types); - if (res.is_valid() && _is_type_valid(res->get_class(), allowed_types)) { - return true; - } + if (res.is_valid()) { + String res_type = _get_resource_type(res); - if (res.is_valid() && res->get_script()) { - StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script()); - if (_is_type_valid(custom_class, allowed_types)) { + if (_is_type_valid(res_type, allowed_types)) { return true; } - } - - if (drag_data.has("type") && String(drag_data["type"]) == "files") { - Vector<String> files = drag_data["files"]; - - if (files.size() == 1) { - String file = files[0]; - String file_type = EditorFileSystem::get_singleton()->get_file_type(file); - if (!file_type.is_empty() && _is_type_valid(file_type, allowed_types)) { - return true; - } + StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res.ptr()); + if (_is_type_valid(custom_class, allowed_types)) { + return true; } } @@ -685,8 +719,10 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ HashSet<String> 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(dropped_resource->get_class(), allowed_types)) { + if (!_is_type_valid(res_type, allowed_types)) { for (const String &E : allowed_types) { String at = E.strip_edges(); diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 3d6127e656..d1a20f04b7 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -91,6 +91,7 @@ class EditorResourcePicker : public HBoxContainer { void _button_draw(); 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; 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; diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index ec67cde112..48e746ac36 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -416,45 +416,50 @@ void EditorSettingsDialog::_update_shortcuts() { List<String> slist; EditorSettings::get_singleton()->get_shortcut_list(&slist); + slist.sort(); // Sort alphabetically. const EditorPropertyNameProcessor::Style name_style = EditorPropertyNameProcessor::get_settings_style(); const EditorPropertyNameProcessor::Style tooltip_style = EditorPropertyNameProcessor::get_tooltip_style(name_style); + // Create all sections first. for (const String &E : slist) { Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E); - if (!sc->has_meta("original")) { + String section_name = E.get_slice("/", 0); + + if (sections.has(section_name)) { continue; } - // Shortcut Section + TreeItem *section = shortcuts->create_item(root); - TreeItem *section; - String section_name = E.get_slice("/", 0); + const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style); - if (sections.has(section_name)) { - section = sections[section_name]; - } else { - section = shortcuts->create_item(root); - - const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style); - - section->set_text(0, item_name); - section->set_tooltip_text(0, tooltip); - section->set_selectable(0, false); - section->set_selectable(1, false); - section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); - section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); - - if (collapsed.has(item_name)) { - section->set_collapsed(collapsed[item_name]); - } + section->set_text(0, item_name); + section->set_tooltip_text(0, tooltip); + section->set_selectable(0, false); + section->set_selectable(1, false); + section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); + section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); - sections[section_name] = section; + if (collapsed.has(item_name)) { + section->set_collapsed(collapsed[item_name]); } - // Shortcut Item + sections[section_name] = section; + } + // Add shortcuts to sections. + for (const String &E : slist) { + Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E); + if (!sc->has_meta("original")) { + continue; + } + + String section_name = E.get_slice("/", 0); + TreeItem *section = sections[section_name]; + + // Shortcut Item if (!shortcut_filter.is_subsequence_ofn(sc->get_name())) { continue; } @@ -552,6 +557,10 @@ void EditorSettingsDialog::_shortcut_cell_double_clicked() { const ShortcutButton edit_btn_id = EditorSettingsDialog::SHORTCUT_EDIT; const int edit_btn_col = 1; TreeItem *ti = shortcuts->get_selected(); + if (ti == nullptr) { + return; + } + String type = ti->get_meta("type"); int col = shortcuts->get_selected_column(); if (type == "shortcut" && col == 0) { diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp index 8c04a4d595..064448fd96 100644 --- a/editor/editor_undo_redo_manager.cpp +++ b/editor/editor_undo_redo_manager.cpp @@ -131,12 +131,12 @@ void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeM void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; - undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount); + undo_redo->add_do_method(Callable(p_object, p_method).bindp(p_args, p_argcount)); } void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; - undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount); + undo_redo->add_undo_method(Callable(p_object, p_method).bindp(p_args, p_argcount)); } void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 8c67885971..43aac5e981 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -865,10 +865,10 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) { if (invalid_path) { export_project->get_ok_button()->set_disabled(true); - export_project->get_line_edit()->disconnect("text_submitted", Callable(export_project, "_file_submitted")); + export_project->get_line_edit()->disconnect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted)); } else { export_project->get_ok_button()->set_disabled(false); - export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted")); + export_project->get_line_edit()->connect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted)); } } @@ -901,9 +901,9 @@ void ProjectExportDialog::_export_project() { // with _validate_export_path. // FIXME: This is a hack, we should instead change EditorFileDialog to allow // disabling validation by the "text_submitted" signal. - if (!export_project->get_line_edit()->is_connected("text_submitted", Callable(export_project, "_file_submitted"))) { + if (!export_project->get_line_edit()->is_connected("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted))) { export_project->get_ok_button()->set_disabled(false); - export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted")); + export_project->get_line_edit()->connect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted)); } export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); diff --git a/editor/icons/VisualScriptComment.svg b/editor/icons/VisualScriptComment.svg deleted file mode 100644 index 3887853b58..0000000000 --- a/editor/icons/VisualScriptComment.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="m3 1v2h-2v2h2v4h-2v2h2v2h2v-2h4v2h2v-2h2v-2h-2v-4h2v-2h-2v-2h-2v2h-4v-2zm2 4h4v4h-4z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/VisualScriptExpression.svg b/editor/icons/VisualScriptExpression.svg deleted file mode 100644 index d6a3c2d9a8..0000000000 --- a/editor/icons/VisualScriptExpression.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m4.859536 3.0412379c-2.0539867 0-3.7190721 1.6650852-3.7190721 3.719072v6.1984521h2.4793814v-2.479381h2.4793814v-2.4793803h-2.4793814v-1.2396908c0-.6846622.5550285-1.2396907 1.2396907-1.2396907h1.2396907v-2.4793813z"/><path d="m7.5889175 3.0000003 2.5000005 4.9999997-2.5000005 5h2.5000005l1.135249-2.727 1.36475 2.727h2.499999l-2.499999-5 2.499999-4.9999997h-2.499999l-1.13525 2.7269998-1.364749-2.7269998zm7.4999985 9.9999997v-6.25z"/></g></svg> diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index d1f37179f3..c1761339b2 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -302,6 +302,7 @@ static UniRange unicode_ranges[] = { { 0x10D00, 0x10D3F, U"Hanifi Rohingya" }, { 0x10E60, 0x10E7F, U"Rumi Numeral Symbols" }, { 0x10E80, 0x10EBF, U"Yezidi" }, + { 0x10EC0, 0x10EFF, U"Arabic Extended-C" }, { 0x10F00, 0x10F2F, U"Old Sogdian" }, { 0x10F30, 0x10F6F, U"Sogdian" }, { 0x10F70, 0x10FAF, U"Old Uyghur" }, @@ -333,11 +334,13 @@ static UniRange unicode_ranges[] = { { 0x11A50, 0x11AAF, U"Soyombo" }, { 0x11AB0, 0x11ABF, U"Unified Canadian Aboriginal Syllabics Extended-A" }, { 0x11AC0, 0x11AFF, U"Pau Cin Hau" }, + { 0x11B00, 0x11B5F, U"Devanagari Extended-A" }, { 0x11C00, 0x11C6F, U"Bhaiksuki" }, { 0x11C70, 0x11CBF, U"Marchen" }, { 0x11D00, 0x11D5F, U"Masaram Gondi" }, { 0x11D60, 0x11DAF, U"Gunjala Gondi" }, { 0x11EE0, 0x11EFF, U"Makasar" }, + { 0x11F00, 0x11F5F, U"Kawi" }, { 0x11FB0, 0x11FBF, U"Lisu Supplement" }, { 0x11FC0, 0x11FFF, U"Tamil Supplement" }, { 0x12000, 0x123FF, U"Cuneiform" }, @@ -370,6 +373,7 @@ static UniRange unicode_ranges[] = { { 0x1D000, 0x1D0FF, U"Byzantine Musical Symbols" }, { 0x1D100, 0x1D1FF, U"Musical Symbols" }, { 0x1D200, 0x1D24F, U"Ancient Greek Musical Notation" }, + { 0x1D2C0, 0x1D2DF, U"Kaktovik Numerals" }, { 0x1D2E0, 0x1D2FF, U"Mayan Numerals" }, { 0x1D300, 0x1D35F, U"Tai Xuan Jing Symbols" }, { 0x1D360, 0x1D37F, U"Counting Rod Numerals" }, @@ -377,9 +381,11 @@ static UniRange unicode_ranges[] = { { 0x1D800, 0x1DAAF, U"Sutton SignWriting" }, { 0x1DF00, 0x1DFFF, U"Latin Extended-G" }, { 0x1E000, 0x1E02F, U"Glagolitic Supplement" }, + { 0x1E030, 0x1E08F, U"Cyrillic Extended-D" }, { 0x1E100, 0x1E14F, U"Nyiakeng Puachue Hmong" }, { 0x1E290, 0x1E2BF, U"Toto" }, { 0x1E2C0, 0x1E2FF, U"Wancho" }, + { 0x1E4D0, 0x1E4FF, U"Nag Mundari" }, { 0x1E7E0, 0x1E7FF, U"Ethiopic Extended-B" }, { 0x1E800, 0x1E8DF, U"Mende Kikakui" }, { 0x1E900, 0x1E95F, U"Adlam" }, @@ -409,6 +415,7 @@ static UniRange unicode_ranges[] = { { 0x2CEB0, 0x2EBEF, U"CJK Unified Ideographs Extension F" }, { 0x2F800, 0x2FA1F, U"CJK Compatibility Ideographs Supplement" }, { 0x30000, 0x3134F, U"CJK Unified Ideographs Extension G" }, + { 0x31350, 0x323AF, U"CJK Unified Ideographs Extension H" }, //{ 0xE0000, 0xE007F, U"Tags" }, //{ 0xE0100, 0xE01EF, U"Variation Selectors Supplement" }, { 0xF0000, 0xFFFFF, U"Supplementary Private Use Area-A" }, diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index f4b8646e18..ca7b2d0015 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -101,13 +101,13 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS); undo_redo->add_do_property(tree, p_property, p_value); undo_redo->add_undo_property(tree, p_property, tree->get(p_property)); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); updating = false; } -void AnimationNodeBlendTreeEditor::_update_graph() { +void AnimationNodeBlendTreeEditor::update_graph() { if (updating || blend_tree.is_null()) { return; } @@ -364,8 +364,8 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { to_slot = -1; } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); } @@ -416,8 +416,8 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve undo_redo->create_action(TTR("Node Moved")); undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE); undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); updating = false; } @@ -437,8 +437,8 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int undo_redo->create_action(TTR("Nodes Connected")); undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from); undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); } @@ -453,8 +453,8 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, undo_redo->create_action(TTR("Nodes Disconnected")); undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index); undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); updating = false; } @@ -468,8 +468,8 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, undo_redo->create_action(TTR("Set Animation")); undo_redo->add_do_method(anim.ptr(), "set_animation", option); undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation()); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); } @@ -491,8 +491,8 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { } } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); } @@ -819,7 +819,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { _update_theme(); if (is_visible_in_tree()) { - _update_graph(); + update_graph(); } } break; @@ -900,12 +900,23 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) { } void AnimationNodeBlendTreeEditor::_bind_methods() { - ClassDB::bind_method("_update_graph", &AnimationNodeBlendTreeEditor::_update_graph); + ClassDB::bind_method("update_graph", &AnimationNodeBlendTreeEditor::update_graph); ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters); } AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr; +// AnimationNode's "node_changed" signal means almost update_input. +void AnimationNodeBlendTreeEditor::_node_changed(const StringName &p_node_name) { + // TODO: + // Here is executed during the commit of EditorNode::undo_redo, it is not possible to create an undo_redo action here. + // The disconnect when the number of enabled inputs decreases is done in AnimationNodeBlendTree and update_graph(). + // This means that there is no place to register undo_redo actions. + // In order to implement undo_redo correctly, we may need to implement AnimationNodeEdit such as AnimationTrackKeyEdit + // and add it to _node_selected() with EditorNode::get_singleton()->push_item(AnimationNodeEdit). + update_graph(); +} + void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) { if (blend_tree.is_null()) { return; @@ -940,8 +951,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name); undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(this, "update_graph"); + undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); updating = false; gn->set_name(new_name); @@ -979,7 +990,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima } } - _update_graph(); // Needed to update the signal connections with the new name. + update_graph(); // Needed to update the signal connections with the new name. } void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) { @@ -996,6 +1007,7 @@ bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) { void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) { if (blend_tree.is_valid()) { + blend_tree->disconnect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed)); blend_tree->disconnect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph)); } @@ -1008,9 +1020,10 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) { } else { read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree); + blend_tree->connect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed)); blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph)); - _update_graph(); + update_graph(); } add_node->set_disabled(read_only); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 30a54930a2..46e0d18c69 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -71,8 +71,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { int to_slot = -1; String from_node = ""; - void _update_graph(); - struct AddOption { String name; String type; @@ -95,6 +93,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which); void _node_renamed(const String &p_text, Ref<AnimationNode> p_node); void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node); + void _node_changed(const StringName &p_node_name); bool updating; @@ -150,6 +149,8 @@ public: virtual bool can_edit(const Ref<AnimationNode> &p_node) override; virtual void edit(const Ref<AnimationNode> &p_node) override; + void update_graph(); + AnimationNodeBlendTreeEditor(); }; diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index ed231c446b..1de4fbaabc 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -50,10 +50,18 @@ #include "scene/scene_string_names.h" void AnimationTreeEditor::edit(AnimationTree *p_tree) { + if (p_tree && !p_tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) { + p_tree->connect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED); + } + if (tree == p_tree) { return; } + if (tree && tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) { + tree->disconnect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed)); + } + tree = p_tree; Vector<String> path; @@ -73,6 +81,13 @@ void AnimationTreeEditor::_path_button_pressed(int p_path) { } } +void AnimationTreeEditor::_animation_list_changed() { + AnimationNodeBlendTreeEditor *bte = AnimationNodeBlendTreeEditor::get_singleton(); + if (bte) { + bte->update_graph(); + } +} + void AnimationTreeEditor::_update_path() { while (path_hb->get_child_count() > 1) { memdelete(path_hb->get_child(1)); diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h index a33d97f62f..9ef9fff8cd 100644 --- a/editor/plugins/animation_tree_editor_plugin.h +++ b/editor/plugins/animation_tree_editor_plugin.h @@ -65,6 +65,7 @@ class AnimationTreeEditor : public VBoxContainer { ObjectID current_root; void _path_button_pressed(int p_path); + void _animation_list_changed(); static Vector<String> get_animation_list(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 070834b33b..8dc08e3a93 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4715,12 +4715,10 @@ void CanvasItemEditor::_reset_drag() { } void CanvasItemEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button); ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data); ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state); ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport); - ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position); ClassDB::bind_method("_set_owner_for_node_and_children", &CanvasItemEditor::_set_owner_for_node_and_children); @@ -4984,8 +4982,8 @@ CanvasItemEditor::CanvasItemEditor() { SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created)); SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position)); - EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", Callable(this, "_update_override_camera_button").bind(true)); - EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", Callable(this, "_update_override_camera_button").bind(false)); + EditorNode::get_singleton()->call_deferred(SNAME("connect"), callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true)); + EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false)); // A fluid container for all toolbars. HFlowContainer *main_flow = memnew(HFlowContainer); @@ -5883,9 +5881,6 @@ void CanvasItemEditorViewport::_notification(int p_what) { } } -void CanvasItemEditorViewport::_bind_methods() { -} - CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_item_editor) { default_texture_node_type = "Sprite2D"; // Node2D diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 0a840d6fd6..b731d3cc7d 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -618,8 +618,6 @@ class CanvasItemEditorViewport : public Control { void _show_resource_type_selector(); void _update_theme(); - static void _bind_methods(); - protected: void _notification(int p_what); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index c8b49678d2..33aad0ac61 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -7645,6 +7645,7 @@ void Node3DEditor::_update_preview_environment() { preview_sun->get_parent()->remove_child(preview_sun); sun_state->show(); sun_vb->hide(); + preview_sun_dangling = true; } if (directional_light_count > 0) { @@ -7658,6 +7659,7 @@ void Node3DEditor::_update_preview_environment() { add_child(preview_sun, true); sun_state->hide(); sun_vb->show(); + preview_sun_dangling = false; } } @@ -7673,6 +7675,7 @@ void Node3DEditor::_update_preview_environment() { preview_environment->get_parent()->remove_child(preview_environment); environ_state->show(); environ_vb->hide(); + preview_env_dangling = true; } if (world_env_count > 0) { environ_state->set_text(TTR("Scene contains\nWorldEnvironment.\nPreview disabled.")); @@ -7685,6 +7688,7 @@ void Node3DEditor::_update_preview_environment() { add_child(preview_environment); environ_state->hide(); environ_vb->show(); + preview_env_dangling = false; } } } @@ -7854,7 +7858,6 @@ Node3DEditor::Node3DEditor() { sun_button->set_toggle_mode(true); sun_button->set_flat(true); sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); - sun_button->set_disabled(true); // Preview is enabled by default - ensure this applies on editor startup when there is no state yet. sun_button->set_pressed(true); @@ -7865,7 +7868,6 @@ Node3DEditor::Node3DEditor() { environ_button->set_toggle_mode(true); environ_button->set_flat(true); environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); - environ_button->set_disabled(true); // Preview is enabled by default - ensure this applies on editor startup when there is no state yet. environ_button->set_pressed(true); @@ -8333,6 +8335,12 @@ void fragment() { } Node3DEditor::~Node3DEditor() { memdelete(preview_node); + if (preview_sun_dangling && preview_sun) { + memdelete(preview_sun); + } + if (preview_env_dangling && preview_environment) { + memdelete(preview_environment); + } } void Node3DEditorPlugin::make_visible(bool p_visible) { diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 580cb878ce..c76f534c22 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -763,7 +763,9 @@ private: Button *sun_environ_settings = nullptr; DirectionalLight3D *preview_sun = nullptr; + bool preview_sun_dangling = false; WorldEnvironment *preview_environment = nullptr; + bool preview_env_dangling = false; Ref<Environment> environment; Ref<CameraAttributesPhysical> camera_attributes; Ref<ProceduralSkyMaterial> sky_material; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 246bc4b183..ae3c578eaa 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -1366,6 +1366,7 @@ void ShaderEditorPlugin::_shader_selected(int p_index) { edited_shaders[p_index].shader_editor->validate_script(); } shader_tabs->set_current_tab(p_index); + shader_list->select(p_index); } void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) { @@ -1375,11 +1376,10 @@ void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_ } void ShaderEditorPlugin::_close_shader(int p_index) { - int index = shader_tabs->get_current_tab(); - ERR_FAIL_INDEX(index, shader_tabs->get_tab_count()); - Control *c = shader_tabs->get_tab_control(index); + ERR_FAIL_INDEX(p_index, shader_tabs->get_tab_count()); + Control *c = shader_tabs->get_tab_control(p_index); memdelete(c); - edited_shaders.remove_at(index); + edited_shaders.remove_at(p_index); _update_shader_list(); EditorNode::get_singleton()->get_undo_redo()->clear_history(); // To prevent undo on deleted graphs. } diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 3ea62184c6..4b2f28658a 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -138,10 +138,6 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) { } } -void Texture3DEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_layer_changed"), &Texture3DEditor::_layer_changed); -} - Texture3DEditor::Texture3DEditor() { set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); set_custom_minimum_size(Size2(1, 150)); @@ -173,7 +169,7 @@ Texture3DEditor::Texture3DEditor() { info->add_theme_constant_override("shadow_offset_y", 2); setting = false; - layer->connect("value_changed", Callable(this, "_layer_changed")); + layer->connect("value_changed", callable_mp(this, &Texture3DEditor::_layer_changed)); } Texture3DEditor::~Texture3DEditor() { diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h index 357bdb0845..7795c83c8a 100644 --- a/editor/plugins/texture_3d_editor_plugin.h +++ b/editor/plugins/texture_3d_editor_plugin.h @@ -66,8 +66,6 @@ class Texture3DEditor : public Control { protected: void _notification(int p_what); - static void _bind_methods(); - public: void edit(Ref<Texture3D> p_texture); Texture3DEditor(); diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index dd8633360e..b0a174c1bc 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -214,10 +214,6 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) { } } -void TextureLayeredEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_layer_changed"), &TextureLayeredEditor::_layer_changed); -} - TextureLayeredEditor::TextureLayeredEditor() { set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); set_custom_minimum_size(Size2(1, 150)); @@ -249,7 +245,7 @@ TextureLayeredEditor::TextureLayeredEditor() { info->add_theme_constant_override("shadow_offset_y", 2); setting = false; - layer->connect("value_changed", Callable(this, "_layer_changed")); + layer->connect("value_changed", callable_mp(this, &TextureLayeredEditor::_layer_changed)); } TextureLayeredEditor::~TextureLayeredEditor() { diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h index f49aa83eb2..f4dbc104c8 100644 --- a/editor/plugins/texture_layered_editor_plugin.h +++ b/editor/plugins/texture_layered_editor_plugin.h @@ -68,7 +68,6 @@ class TextureLayeredEditor : public Control { protected: void _notification(int p_what); virtual void gui_input(const Ref<InputEvent> &p_event) override; - static void _bind_methods(); public: void edit(Ref<TextureLayered> p_texture); diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index d9291503cb..c823487279 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -403,6 +403,9 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_ // Update everything. _update_zoom_and_panning(); + base_tiles_drawing_root->set_size(_compute_base_tiles_control_size()); + alternative_tiles_drawing_root->set_size(_compute_alternative_tiles_control_size()); + // Update. base_tiles_draw->queue_redraw(); base_tiles_texture_grid->queue_redraw(); @@ -601,7 +604,6 @@ TileAtlasView::TileAtlasView() { base_tiles_drawing_root = memnew(Control); base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); base_tiles_root_control->add_child(base_tiles_drawing_root); @@ -645,7 +647,6 @@ TileAtlasView::TileAtlasView() { alternative_tiles_drawing_root = memnew(Control); alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); alternative_tiles_root_control->add_child(alternative_tiles_drawing_root); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 228e475083..45b2a5eb14 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -401,7 +401,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro if (all_alternatve_id_zero) { p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP)); p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "")); - p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, "suffix:px")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_")); // Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does. diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index ee8148f00a..7c4326cde1 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1358,7 +1358,7 @@ void VisualShaderEditor::_update_options_menu() { Color unsupported_color = get_theme_color(SNAME("error_color"), SNAME("Editor")); Color supported_color = get_theme_color(SNAME("warning_color"), SNAME("Editor")); - static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "opengl3"; + static bool low_driver = ProjectSettings::get_singleton()->get("rendering/renderer/rendering_method") == "gl_compatibility"; HashMap<String, TreeItem *> folders; diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 39b30b31fb..8df59c286c 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -38,6 +38,7 @@ const int ERROR_CODE = 77; #include "modules/regex/regex.h" +#include "core/io/dir_access.h" #include "core/os/time.h" #include "core/templates/hash_map.h" #include "core/templates/list.h" @@ -2229,22 +2230,23 @@ Vector<String> ProjectConverter3To4::check_for_files() { Vector<String> directories_to_check = Vector<String>(); directories_to_check.push_back("res://"); - core_bind::Directory dir = core_bind::Directory(); while (!directories_to_check.is_empty()) { String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function? - directories_to_check.resize(directories_to_check.size() - 1); // Remove last element. - if (dir.open(path) == OK) { - dir.set_include_hidden(true); - dir.list_dir_begin(); - String current_dir = dir.get_current_dir(); - String file_name = dir.get_next(); + directories_to_check.resize(directories_to_check.size() - 1); // Remove last element + + Ref<DirAccess> dir = DirAccess::create_for_path(path); + if (dir.is_valid()) { + dir->set_include_hidden(true); + dir->list_dir_begin(); + String current_dir = dir->get_current_dir(); + String file_name = dir->_get_next(); while (file_name != "") { if (file_name == ".git" || file_name == ".import" || file_name == ".godot") { - file_name = dir.get_next(); + file_name = dir->_get_next(); continue; } - if (dir.current_is_dir()) { + if (dir->current_is_dir()) { directories_to_check.append(current_dir.path_join(file_name) + "/"); } else { bool proper_extension = false; @@ -2255,7 +2257,7 @@ Vector<String> ProjectConverter3To4::check_for_files() { collected_files.append(current_dir.path_join(file_name)); } } - file_name = dir.get_next(); + file_name = dir->_get_next(); } } else { print_verbose("Failed to open " + path); @@ -3950,6 +3952,8 @@ String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector) #else // No RegEx. +ProjectConverter3To4::ProjectConverter3To4(int _p_maximum_file_size_kb, int _p_maximum_line_length) {} + int ProjectConverter3To4::convert() { ERR_FAIL_V_MSG(ERROR_CODE, "Can't run converter for Godot 3.x projects, because RegEx module is disabled."); } diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index 2cecb9da79..d03e645ac7 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -31,7 +31,6 @@ #ifndef PROJECT_CONVERTER_3_TO_4_H #define PROJECT_CONVERTER_3_TO_4_H -#include "core/core_bind.h" #include "core/io/file_access.h" #include "core/object/ref_counted.h" #include "core/string/ustring.h" diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 69a2670418..673da8872d 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -92,9 +92,9 @@ private: Container *name_container; Container *path_container; Container *install_path_container; - Container *rasterizer_container; + Container *renderer_container; HBoxContainer *default_files_container; - Ref<ButtonGroup> rasterizer_button_group; + Ref<ButtonGroup> renderer_button_group; Label *msg; LineEdit *project_path; LineEdit *project_name; @@ -473,16 +473,19 @@ private: } PackedStringArray project_features = ProjectSettings::get_required_features(); ProjectSettings::CustomMap initial_settings; + // Be sure to change this code if/when renderers are changed. - int renderer_type = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name")); - initial_settings["rendering/vulkan/rendering/back_end"] = renderer_type; - if (renderer_type == 0) { - project_features.push_back("Vulkan Clustered"); - } else if (renderer_type == 1) { - project_features.push_back("Vulkan Mobile"); + String renderer_type = renderer_button_group->get_pressed_button()->get_meta(SNAME("rendering_method")); + initial_settings["rendering/renderer/rendering_method"] = renderer_type; + + if (renderer_type == "forward_plus") { + project_features.push_back("Forward Plus"); + } else if (renderer_type == "mobile") { + project_features.push_back("Mobile"); } else { WARN_PRINT("Unknown renderer type. Please report this as a bug on GitHub."); } + project_features.sort(); initial_settings["application/config/features"] = project_features; initial_settings["application/config/name"] = project_name->get_text().strip_edges(); @@ -684,7 +687,7 @@ public: msg->hide(); install_path_container->hide(); install_status_rect->hide(); - rasterizer_container->hide(); + renderer_container->hide(); default_files_container->hide(); get_ok_button()->set_disabled(false); @@ -735,7 +738,7 @@ public: set_ok_button_text(TTR("Import & Edit")); name_container->hide(); install_path_container->hide(); - rasterizer_container->hide(); + renderer_container->hide(); default_files_container->hide(); project_path->grab_focus(); @@ -744,7 +747,7 @@ public: set_ok_button_text(TTR("Create & Edit")); name_container->show(); install_path_container->hide(); - rasterizer_container->show(); + renderer_container->show(); default_files_container->show(); project_name->call_deferred(SNAME("grab_focus")); project_name->call_deferred(SNAME("select_all")); @@ -755,7 +758,7 @@ public: project_name->set_text(zip_title); name_container->show(); install_path_container->hide(); - rasterizer_container->hide(); + renderer_container->hide(); default_files_container->hide(); project_path->grab_focus(); } @@ -843,23 +846,23 @@ public: msg->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); vb->add_child(msg); - // rasterizer selection - rasterizer_container = memnew(VBoxContainer); - vb->add_child(rasterizer_container); + // Renderer selection. + renderer_container = memnew(VBoxContainer); + vb->add_child(renderer_container); l = memnew(Label); l->set_text(TTR("Renderer:")); - rasterizer_container->add_child(l); - Container *rshb = memnew(HBoxContainer); - rasterizer_container->add_child(rshb); - rasterizer_button_group.instantiate(); + renderer_container->add_child(l); + HBoxContainer *rshc = memnew(HBoxContainer); + renderer_container->add_child(rshc); + renderer_button_group.instantiate(); Container *rvb = memnew(VBoxContainer); rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL); - rshb->add_child(rvb); + rshc->add_child(rvb); Button *rs_button = memnew(CheckBox); - rs_button->set_button_group(rasterizer_button_group); - rs_button->set_text(TTR("Vulkan Clustered")); - rs_button->set_meta(SNAME("driver_name"), 0); // Vulkan backend "Forward Clustered" + rs_button->set_button_group(renderer_button_group); + rs_button->set_text(TTR("Forward+")); + rs_button->set_meta(SNAME("rendering_method"), "forward_plus"); rs_button->set_pressed(true); rvb->add_child(rs_button); l = memnew(Label); @@ -871,15 +874,15 @@ public: l->set_modulate(Color(1, 1, 1, 0.7)); rvb->add_child(l); - rshb->add_child(memnew(VSeparator)); + rshc->add_child(memnew(VSeparator)); rvb = memnew(VBoxContainer); rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL); - rshb->add_child(rvb); + rshc->add_child(rvb); rs_button = memnew(CheckBox); - rs_button->set_button_group(rasterizer_button_group); - rs_button->set_text(TTR("Vulkan Mobile")); - rs_button->set_meta(SNAME("driver_name"), 1); // Vulkan backend "Forward Mobile" + rs_button->set_button_group(renderer_button_group); + rs_button->set_text(TTR("Mobile")); + rs_button->set_meta(SNAME("rendering_method"), "mobile"); rvb->add_child(rs_button); l = memnew(Label); l->set_text( @@ -897,7 +900,7 @@ public: l->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); l->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); l->set_modulate(Color(1, 1, 1, 0.7)); - rasterizer_container->add_child(l); + renderer_container->add_child(l); default_files_container = memnew(HBoxContainer); vb->add_child(default_files_container); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index a437245c57..aefb2c78c1 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -135,6 +135,8 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) { _tool_selected(TOOL_ERASE, true); } else if (ED_IS_SHORTCUT("scene_tree/copy_node_path", p_event)) { _tool_selected(TOOL_COPY_NODE_PATH); + } else if (ED_IS_SHORTCUT("scene_tree/toggle_unique_name", p_event)) { + _tool_selected(TOOL_TOGGLE_SCENE_UNIQUE_NAME); } else if (ED_IS_SHORTCUT("scene_tree/delete", p_event)) { _tool_selected(TOOL_ERASE); } else { @@ -916,6 +918,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { String existing; if (extensions.size()) { String root_name(tocopy->get_name()); + root_name = EditorNode::adjust_scene_name_casing(root_name); existing = root_name + "." + extensions.front()->get().to_lower(); } new_scene_from_dialog->set_current_path(existing); @@ -1073,6 +1076,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (first_selected == nullptr) { return; } + if (first_selected->get() == EditorNode::get_singleton()->get_edited_scene()) { + // Exclude Root Node. It should never be unique name in its own scene! + editor_selection->remove_node(first_selected->get()); + first_selected = editor_selection->get_selected_node_list().front(); + if (first_selected == nullptr) { + return; + } + } bool enabling = !first_selected->get()->is_unique_name_in_owner(); List<Node *> full_selection = editor_selection->get_full_selected_node_list(); @@ -1235,14 +1246,14 @@ void SceneTreeDock::_notification(int p_what) { CanvasItemEditorPlugin *canvas_item_plugin = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor("2D")); if (canvas_item_plugin) { - canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree")); - canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree")); + canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree)); + canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree)); scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw)); } Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D")); - spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree")); - spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree")); + spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree)); + spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree)); button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); @@ -2865,10 +2876,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } } if (all_owned) { - menu->add_separator(); - menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME); - // Checked based on `selection[0]` because `full_selection` has undesired ordering. - menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner()); + // Group "toggle_unique_name" with "copy_node_path", if it is available. + if (menu->get_item_index(TOOL_COPY_NODE_PATH) == -1) { + menu->add_separator(); + } + Node *node = full_selection[0]; + menu->add_icon_shortcut(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/toggle_unique_name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME); + menu->set_item_text(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), node->is_unique_name_in_owner() ? TTR("Revoke Unique Name") : TTR("Access as Unique Name")); } } @@ -3421,6 +3435,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root")); ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene")); ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C); + ED_SHORTCUT("scene_tree/toggle_unique_name", TTR("Toggle Access as Unique Name")); ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KeyModifierMask::SHIFT | Key::KEY_DELETE); ED_SHORTCUT("scene_tree/delete", TTR("Delete"), Key::KEY_DELETE); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 137574640e..6fff2ab7cb 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -835,7 +835,7 @@ void SceneTreeEditor::_notification(int p_what) { get_tree()->connect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed)); get_tree()->connect("node_removed", callable_mp(this, &SceneTreeEditor::_node_removed)); get_tree()->connect("node_renamed", callable_mp(this, &SceneTreeEditor::_node_renamed)); - get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed), CONNECT_DEFERRED); + get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed)); tree->connect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed)); @@ -1332,7 +1332,7 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) { } void SceneTreeEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by some connect_compat. + ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by UndoRedo. ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node); ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree); diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 28ffa4b11b..8fbc3ab6d6 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -76,7 +76,6 @@ class SceneTreeEditor : public Control { void _add_nodes(Node *p_node, TreeItem *p_parent); void _test_update_tree(); - void _update_tree(bool p_scroll_to_selected = false); bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false); bool _item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms); void _tree_changed(); @@ -138,6 +137,9 @@ class SceneTreeEditor : public Control { Vector<StringName> valid_types; public: + // Public for use with callable_mp. + void _update_tree(bool p_scroll_to_selected = false); + void set_filter(const String &p_filter); String get_filter() const; diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index eef0f3eae1..473bbd69d9 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -483,7 +483,7 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() { inspector->connect("property_deleted", callable_mp(this, &ShaderGlobalsEditor::_variable_deleted), CONNECT_DEFERRED); interface = memnew(ShaderGlobalsEditorInterface); - interface->connect("var_changed", Callable(this, "_changed")); + interface->connect("var_changed", callable_mp(this, &ShaderGlobalsEditor::_changed)); } ShaderGlobalsEditor::~ShaderGlobalsEditor() { diff --git a/main/main.cpp b/main/main.cpp index a338b71154..5fd3786af9 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -141,6 +141,7 @@ static bool _start_success = false; String tablet_driver = ""; String text_driver = ""; String rendering_driver = ""; +String rendering_method = ""; static int text_driver_idx = -1; static int display_driver_idx = -1; static int audio_driver_idx = -1; @@ -353,6 +354,7 @@ void Main::print_help(const char *p_binary) { } OS::get_singleton()->print("].\n"); + OS::get_singleton()->print(" --rendering-method <renderer> Renderer name. Requires driver support.\n"); OS::get_singleton()->print(" --rendering-driver <driver> Rendering driver (depends on display driver).\n"); OS::get_singleton()->print(" --gpu-index <device_index> Use a specific GPU (run with --verbose to get available device list).\n"); OS::get_singleton()->print(" --text-driver <driver> Text driver (Fonts, BiDi, shaping)\n"); @@ -757,6 +759,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } if (I->get() == "--audio-driver" || I->get() == "--display-driver" || + I->get() == "--rendering-method" || I->get() == "--rendering-driver") { if (I->next()) { forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); @@ -866,43 +869,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->print("Missing display driver argument, aborting.\n"); goto error; } + } else if (I->get() == "--rendering-method") { + if (I->next()) { + rendering_method = I->next()->get(); + N = I->next()->next(); + } else { + OS::get_singleton()->print("Missing renderer name argument, aborting.\n"); + goto error; + } } else if (I->get() == "--rendering-driver") { if (I->next()) { rendering_driver = I->next()->get(); - - // as the rendering drivers available may depend on the display driver selected, - // we can't do an exhaustive check here, but we can look through all the options in - // all the display drivers for a match - - bool found = false; - for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { - Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i); - - for (int d = 0; d < r_drivers.size(); d++) { - if (rendering_driver == r_drivers[d]) { - found = true; - break; - } - } - } - - if (!found) { - OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ", - rendering_driver.utf8().get_data()); - - for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { - Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i); - - for (int d = 0; d < r_drivers.size(); d++) { - OS::get_singleton()->print("'%s', ", r_drivers[d].utf8().get_data()); - } - } - - OS::get_singleton()->print(".\n"); - - goto error; - } - N = I->next()->next(); } else { OS::get_singleton()->print("Missing rendering driver argument, aborting.\n"); @@ -1485,45 +1462,188 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->set_cmdline(execpath, main_args, user_args); - // possibly be worth changing the default from vulkan to something lower spec, - // for the project manager, depending on how smooth the fallback is. + { + String driver_hints = ""; +#ifdef VULKAN_ENABLED + driver_hints = "vulkan"; +#endif - // this list is hard coded, which makes it more difficult to add new backends. - // can potentially be changed to more of a plugin system at a later date. + String default_driver = driver_hints.get_slice(",", 0); + + // For now everything defaults to vulkan when available. This can change in future updates. + GLOBAL_DEF("rendering/rendering_device/driver", default_driver); + GLOBAL_DEF("rendering/rendering_device/driver.windows", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.windows", + PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/rendering_device/driver.linuxbsd", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.linuxbsd", + PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/rendering_device/driver.android", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.android", + PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/rendering_device/driver.ios", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.ios", + PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/rendering_device/driver.macos", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.macos", + PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, driver_hints)); + + driver_hints = ""; +#ifdef GLES3_ENABLED + driver_hints += "opengl3"; +#endif - // Start with Vulkan, which will be the default if enabled. + default_driver = driver_hints.get_slice(",", 0); + + GLOBAL_DEF("rendering/gl_compatibility/driver", default_driver); + GLOBAL_DEF("rendering/gl_compatibility/driver.windows", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.windows", + PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/gl_compatibility/driver.linuxbsd", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.linuxbsd", + PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/gl_compatibility/driver.web", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.web", + PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/gl_compatibility/driver.android", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.android", + PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/gl_compatibility/driver.ios", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.ios", + PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints)); + GLOBAL_DEF("rendering/gl_compatibility/driver.macos", default_driver); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.macos", + PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints)); + } + + // Start with RenderingDevice-based backends. Should be included if any RD driver present. #ifdef VULKAN_ENABLED - renderer_hints = "vulkan"; + renderer_hints = "forward_plus,mobile"; #endif - // And OpenGL3 next, or first if Vulkan is disabled. + // And Compatibility next, or first if Vulkan is disabled. #ifdef GLES3_ENABLED if (!renderer_hints.is_empty()) { renderer_hints += ","; } - renderer_hints += "opengl3"; + renderer_hints += "gl_compatibility"; #endif if (renderer_hints.is_empty()) { - ERR_PRINT("No rendering driver available."); + ERR_PRINT("No renderers available."); + } + + if (!rendering_method.is_empty()) { + if (rendering_method != "forward_plus" && + rendering_method != "mobile" && + rendering_method != "gl_compatibility") { + OS::get_singleton()->print("Unknown renderer name '%s', aborting. Valid options are: %s\n", rendering_method.utf8().get_data(), renderer_hints.utf8().get_data()); + goto error; + } + } + + if (!rendering_driver.is_empty()) { + // As the rendering drivers available may depend on the display driver and renderer + // selected, we can't do an exhaustive check here, but we can look through all + // the options in all the display drivers for a match. + + bool found = false; + for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { + Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i); + + for (int d = 0; d < r_drivers.size(); d++) { + if (rendering_driver == r_drivers[d]) { + found = true; + break; + } + } + } + + if (!found) { + OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ", + rendering_driver.utf8().get_data()); + + for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { + Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i); + + for (int d = 0; d < r_drivers.size(); d++) { + OS::get_singleton()->print("'%s', ", r_drivers[d].utf8().get_data()); + } + } + + OS::get_singleton()->print(".\n"); + + goto error; + } + + // Set a default renderer if none selected. Try to choose one that matches the driver. + if (rendering_method.is_empty()) { + if (rendering_driver == "opengl3") { + rendering_method = "gl_compatibility"; + } else { + rendering_method = "forward_plus"; + } + } + + // Now validate whether the selected driver matches with the renderer. + bool valid_combination = false; + Vector<String> available_drivers; + if (rendering_method == "forward_plus" || rendering_method == "mobile") { + available_drivers.push_back("vulkan"); + } else if (rendering_method == "gl_compatibility") { + available_drivers.push_back("opengl3"); + } else { + OS::get_singleton()->print("Unknown renderer name '%s', aborting.\n", rendering_method.utf8().get_data()); + goto error; + } + + for (int i = 0; i < available_drivers.size(); i++) { + if (rendering_driver == available_drivers[i]) { + valid_combination = true; + break; + } + } + + if (!valid_combination) { + OS::get_singleton()->print("Invalid renderer/driver combination '%s' and '%s', aborting. %s only supports the following drivers ", rendering_method.utf8().get_data(), rendering_driver.utf8().get_data(), rendering_method.utf8().get_data()); + + for (int d = 0; d < available_drivers.size(); d++) { + OS::get_singleton()->print("'%s', ", available_drivers[d].utf8().get_data()); + } + + OS::get_singleton()->print(".\n"); + + goto error; + } } default_renderer = renderer_hints.get_slice(",", 0); - GLOBAL_DEF_RST("rendering/driver/driver_name", default_renderer); + GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method", default_renderer); + GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.mobile", default_renderer); + GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.web", "gl_compatibility"); // This is a bit of a hack until we have WebGPU support. - ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name", + ProjectSettings::get_singleton()->set_custom_property_info("rendering/renderer/rendering_method", PropertyInfo(Variant::STRING, - "rendering/driver/driver_name", + "rendering/renderer/rendering_method", PROPERTY_HINT_ENUM, renderer_hints)); - // if not set on the command line + // Default to ProjectSettings default if nothing set on the command line. + if (rendering_method.is_empty()) { + rendering_method = GLOBAL_GET("rendering/renderer/rendering_method"); + } + if (rendering_driver.is_empty()) { - rendering_driver = GLOBAL_GET("rendering/driver/driver_name"); + if (rendering_method == "gl_compatibility") { + rendering_driver = GLOBAL_GET("rendering/gl_compatibility/driver"); + } else { + rendering_driver = GLOBAL_GET("rendering/rendering_device/driver"); + } } // note this is the desired rendering driver, it doesn't mean we will get it. // TODO - make sure this is updated in the case of fallbacks, so that the user interface // shows the correct driver string. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); + OS::get_singleton()->set_current_rendering_method(rendering_method); // always convert to lower case for consistency in the code rendering_driver = rendering_driver.to_lower(); diff --git a/methods.py b/methods.py index 1f49da7ace..78ec9b8674 100644 --- a/methods.py +++ b/methods.py @@ -77,44 +77,37 @@ def add_module_version_string(self, s): self.module_version_string += "." + s -def update_version(module_version_string=""): +def get_version_info(module_version_string="", silent=False): build_name = "custom_build" if os.getenv("BUILD_NAME") != None: build_name = str(os.getenv("BUILD_NAME")) - print("Using custom build name: " + build_name) + if not silent: + print(f"Using custom build name: '{build_name}'.") import version - # NOTE: It is safe to generate this file here, since this is still executed serially - f = open("core/version_generated.gen.h", "w") - f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - f.write("#ifndef VERSION_GENERATED_GEN_H\n") - f.write("#define VERSION_GENERATED_GEN_H\n") - f.write('#define VERSION_SHORT_NAME "' + str(version.short_name) + '"\n') - f.write('#define VERSION_NAME "' + str(version.name) + '"\n') - f.write("#define VERSION_MAJOR " + str(version.major) + "\n") - f.write("#define VERSION_MINOR " + str(version.minor) + "\n") - f.write("#define VERSION_PATCH " + str(version.patch) + "\n") + version_info = { + "short_name": str(version.short_name), + "name": str(version.name), + "major": int(version.major), + "minor": int(version.minor), + "patch": int(version.patch), + "status": str(version.status), + "build": str(build_name), + "module_config": str(version.module_config) + module_version_string, + "year": int(version.year), + "website": str(version.website), + "docs_branch": str(version.docs), + } + # For dev snapshots (alpha, beta, RC, etc.) we do not commit status change to Git, # so this define provides a way to override it without having to modify the source. - godot_status = str(version.status) if os.getenv("GODOT_VERSION_STATUS") != None: - godot_status = str(os.getenv("GODOT_VERSION_STATUS")) - print("Using version status '{}', overriding the original '{}'.".format(godot_status, str(version.status))) - f.write('#define VERSION_STATUS "' + godot_status + '"\n') - f.write('#define VERSION_BUILD "' + str(build_name) + '"\n') - f.write('#define VERSION_MODULE_CONFIG "' + str(version.module_config) + module_version_string + '"\n') - f.write("#define VERSION_YEAR " + str(version.year) + "\n") - f.write('#define VERSION_WEBSITE "' + str(version.website) + '"\n') - f.write('#define VERSION_DOCS_BRANCH "' + str(version.docs) + '"\n') - f.write('#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH\n') - f.write("#endif // VERSION_GENERATED_GEN_H\n") - f.close() + version_info["status"] = str(os.getenv("GODOT_VERSION_STATUS")) + if not silent: + print(f"Using version status '{version_info.status}', overriding the original '{version.status}'.") - # NOTE: It is safe to generate this file here, since this is still executed serially - fhash = open("core/version_hash.gen.cpp", "w") - fhash.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - fhash.write('#include "core/version.h"\n') + # Parse Git hash if we're in a Git repo. githash = "" gitfolder = ".git" @@ -144,7 +137,49 @@ def update_version(module_version_string=""): else: githash = head - fhash.write('const char *const VERSION_HASH = "' + githash + '";\n') + version_info["git_hash"] = githash + + return version_info + + +def generate_version_header(module_version_string=""): + version_info = get_version_info(module_version_string) + + # NOTE: It is safe to generate these files here, since this is still executed serially. + + f = open("core/version_generated.gen.h", "w") + f.write( + """/* THIS FILE IS GENERATED DO NOT EDIT */ +#ifndef VERSION_GENERATED_GEN_H +#define VERSION_GENERATED_GEN_H +#define VERSION_SHORT_NAME "{short_name}" +#define VERSION_NAME "{name}" +#define VERSION_MAJOR {major} +#define VERSION_MINOR {minor} +#define VERSION_PATCH {patch} +#define VERSION_STATUS "{status}" +#define VERSION_BUILD "{build}" +#define VERSION_MODULE_CONFIG "{module_config}" +#define VERSION_YEAR {year} +#define VERSION_WEBSITE "{website}" +#define VERSION_DOCS_BRANCH "{docs_branch}" +#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH +#endif // VERSION_GENERATED_GEN_H +""".format( + **version_info + ) + ) + f.close() + + fhash = open("core/version_hash.gen.cpp", "w") + fhash.write( + """/* THIS FILE IS GENERATED DO NOT EDIT */ +#include "core/version.h" +const char *const VERSION_HASH = "{git_hash}"; +""".format( + **version_info + ) + ) fhash.close() diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html index 7c44dd45a1..ac00270d50 100644 --- a/misc/dist/html/editor.html +++ b/misc/dist/html/editor.html @@ -259,31 +259,20 @@ >Web editor documentation</a> for usage instructions and limitations. </p> </div> - <div id="welcome-modal-description-no-cross-origin-isolation" style="display: none"> + <div id="welcome-modal-missing-description" style="display: none"> <p> - The web server does not support cross-origin isolation, - which is required for the Godot Web Editor to function. - </p> - <p> - <strong>Reasons for cross-origin isolation being disabled:</strong> - <ul> - <li id="welcome-modal-reason-not-secure"> - This page is not served from a secure context (HTTPS <i>or</i> localhost). - </li> - <li> - This page may not be served with cross-origin isolation headers - (check with the developer tools' Network tab). - </li> + <strong>The following features required by the Godot Web Editor are missing:</strong> + <ul id="welcome-modal-missing-list"> </ul> </p> <p> If you are self-hosting the web editor, refer to <a - href="https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html#threads" + href="https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html" target="_blank" rel="noopener" - >Exporting for the Web - Threads</a> for more information. + >Exporting for the Web</a> for more information. </p> </div> <div style="text-align: center"> @@ -394,16 +383,22 @@ }); } - if (!crossOriginIsolated) { + const missing = Engine.getMissingFeatures(); + if (missing.length) { // Display error dialog as threading support is required for the editor. setButtonEnabled('startButton', false); document.getElementById("welcome-modal-description").style.display = "none"; - document.getElementById("welcome-modal-description-no-cross-origin-isolation").style.display = "block"; + document.getElementById("welcome-modal-missing-description").style.display = "block"; document.getElementById("welcome-modal-dismiss").style.display = "none"; - document.getElementById("welcome-modal-reason-not-secure").style.display = window.isSecureContext ? "none" : "list-item"; + const list = document.getElementById("welcome-modal-missing-list"); + for (let i = 0; i < missing.length; i++) { + const node = document.createElement("li"); + node.innerText = missing[i]; + list.appendChild(node); + } } - if (!crossOriginIsolated || localStorage.getItem("welcomeModalDismissed") !== 'true') { + if (missing.length || localStorage.getItem("welcomeModalDismissed") !== 'true') { document.getElementById("welcome-modal").style.display = "block"; document.getElementById("welcome-modal-dismiss").focus(); } diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html index f385b82f1d..d5b0050cfd 100644 --- a/misc/dist/html/full-size.html +++ b/misc/dist/html/full-size.html @@ -215,8 +215,10 @@ $GODOT_HEAD_INCLUDE initializing = false; }; - if (!Engine.isWebGLAvailable()) { - displayFailureNotice('WebGL not available'); + const missing = Engine.getMissingFeatures(); + if (missing.length !== 0) { + const missingMsg = 'Warning!\nThe following features required to run Godot projects on the Web are missing:\n'; + displayFailureNotice(missingMsg + missing.join("\n")); } else { setStatusMode('indeterminate'); engine.startGame({ diff --git a/misc/dist/shell/_godot.zsh-completion b/misc/dist/shell/_godot.zsh-completion index b17bb6e66b..2bc6fe9317 100644 --- a/misc/dist/shell/_godot.zsh-completion +++ b/misc/dist/shell/_godot.zsh-completion @@ -44,6 +44,7 @@ _arguments \ '--remote-fs-password[password for remote filesystem]:remote filesystem password' \ '--audio-driver[set the audio driver]:audio driver name' \ '--display-driver[set the display driver]:display driver name' \ + "--rendering-method[set the renderer]:renderer name:((forward_plus\:'Desktop renderer' mobile\:'Desktop and mobile renderer' gl_compatibility\:'Desktop, mobile and web renderer'))" \ "--rendering-driver[set the rendering driver]:rendering driver name:((vulkan\:'Vulkan renderer' opengl3\:'OpenGL ES 3.0 renderer' dummy\:'Dummy renderer'))" \ "--gpu-index[use a specific GPU (run with --verbose to get available device list)]:device index" \ '--text-driver[set the text driver]:text driver name' \ diff --git a/misc/dist/shell/godot.bash-completion b/misc/dist/shell/godot.bash-completion index 1ab687e1fc..bc5fa600f5 100644 --- a/misc/dist/shell/godot.bash-completion +++ b/misc/dist/shell/godot.bash-completion @@ -47,6 +47,7 @@ _complete_godot_options() { --remote-fs-password --audio-driver --display-driver +--rendering-method --rendering-driver --gpu-index --text-driver @@ -58,7 +59,6 @@ _complete_godot_options() { --always-on-top --resolution --position ---headless --single-window --debug --breakpoints @@ -112,6 +112,10 @@ _complete_godot_bash() { local IFS=$' \n\t' # shellcheck disable=SC2207 COMPREPLY=($(compgen -W "unsafe safe separate" -- "$cur")) + elif [[ $prev == "--rendering-method" ]]; then + local IFS=$' \n\t' + # shellcheck disable=SC2207 + COMPREPLY=($(compgen -W "forward_plus mobile gl_compatibility" -- "$cur")) elif [[ $prev == "--rendering-driver" ]]; then local IFS=$' \n\t' # shellcheck disable=SC2207 diff --git a/misc/dist/shell/godot.fish b/misc/dist/shell/godot.fish index d58066c135..9ac692eace 100644 --- a/misc/dist/shell/godot.fish +++ b/misc/dist/shell/godot.fish @@ -23,6 +23,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +function godot_rendering_method_args + # Use a function instead of a fixed string to customize the argument descriptions. + echo -e "forward_plus\tHigh-end desktop renderer" + echo -e "mobile\tHigh-end mobile/desktop renderer" + echo -e "gl_compatibility\tLow-end desktop, mobile and web renderer" +end + function godot_rendering_driver_args # Use a function instead of a fixed string to customize the argument descriptions. echo -e "vulkan\tVulkan renderer" @@ -53,6 +60,7 @@ complete -c godot -l remote-fs -d "Use a remote filesystem (<host/IP>[:<port>] a complete -c godot -l remote-fs-password -d "Password for remote filesystem" -x complete -c godot -l audio-driver -d "Set the audio driver" -x complete -c godot -l display-driver -d "Set the display driver" -x +complete -c godot -l rendering-method -d "Set the renderer" -x -a "(godot_rendering_method_args)" complete -c godot -l rendering-driver -d "Set the rendering driver" -x -a "(godot_rendering_driver_args)" complete -c godot -l gpu-index -d "Use a specific GPU (run with --verbose to get available device list)" -x complete -c godot -l text-driver -d "Set the text driver" -x diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index ae03abca50..cc21ed28e8 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -200,7 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, return err; } -Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { bmp_header_s bmp_header; Error err = ERR_INVALID_DATA; diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h index cf8346ecad..0ca54de1dc 100644 --- a/modules/bmp/image_loader_bmp.h +++ b/modules/bmp/image_loader_bmp.h @@ -83,7 +83,7 @@ protected: const bmp_header_s &p_header); public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderBMP(); }; diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp index 7c4a2085b2..67858e9d46 100644 --- a/modules/bmp/register_types.cpp +++ b/modules/bmp/register_types.cpp @@ -32,14 +32,14 @@ #include "image_loader_bmp.h" -static ImageLoaderBMP *image_loader_bmp = nullptr; +static Ref<ImageLoaderBMP> image_loader_bmp; void initialize_bmp_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - image_loader_bmp = memnew(ImageLoaderBMP); + image_loader_bmp.instantiate(); ImageLoader::add_image_format_loader(image_loader_bmp); } @@ -48,5 +48,6 @@ void uninitialize_bmp_module(ModuleInitializationLevel p_level) { return; } - memdelete(image_loader_bmp); + ImageLoader::remove_image_format_loader(image_loader_bmp); + image_loader_bmp.unref(); } diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 4f325fcf52..6cf8c1a30e 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -555,7 +555,7 @@ <annotation name="@onready"> <return type="void" /> <description> - Mark the following property as assigned on [Node]'s ready state change. Values for these properties are no assigned immediately upon the node's creation, and instead are computed and stored right before [method Node._ready]. + Mark the following property as assigned on [Node]'s ready state change. Values for these properties are not assigned immediately upon the node's creation, and instead are computed and stored right before [method Node._ready]. [codeblock] @onready var character_name: Label = $Label [/codeblock] diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index e37ac1dc3b..32d9aec84f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -484,12 +484,23 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type if (parser->script_path == ScriptServer::get_global_class_path(first)) { result = parser->head->get_datatype(); } else { - Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(first)); - if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) { - push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type); - return GDScriptParser::DataType(); + String path = ScriptServer::get_global_class_path(first); + String ext = path.get_extension(); + if (ext == GDScriptLanguage::get_singleton()->get_extension()) { + Ref<GDScriptParserRef> ref = get_parser_for(path); + if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) { + push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type); + return GDScriptParser::DataType(); + } + result = ref->get_parser()->head->get_datatype(); + } else { + result.kind = GDScriptParser::DataType::SCRIPT; + result.native_type = ScriptServer::get_global_class_native_base(first); + result.script_type = ResourceLoader::load(path, "Script"); + result.script_path = path; + result.is_constant = true; + result.is_meta_type = false; } - result = ref->get_parser()->head->get_datatype(); } } else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) { const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first); @@ -540,12 +551,13 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type result = ref->get_parser()->head->get_datatype(); result.is_meta_type = false; } else { - Ref<GDScript> script = member.constant->initializer->reduced_value; + Ref<Script> script = member.constant->initializer->reduced_value; result.kind = GDScriptParser::DataType::SCRIPT; result.builtin_type = Variant::OBJECT; result.script_type = script; result.script_path = script->get_path(); result.native_type = script->get_instance_base_type(); + result.is_meta_type = false; } break; } @@ -2676,31 +2688,45 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node) GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) { GDScriptParser::DataType type; - Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(p_class_name)); - if (ref.is_null()) { - push_error(vformat(R"(Could not find script for class "%s".)", p_class_name), p_source); - type.type_source = GDScriptParser::DataType::UNDETECTED; - type.kind = GDScriptParser::DataType::VARIANT; + String path = ScriptServer::get_global_class_path(p_class_name); + String ext = path.get_extension(); + if (ext == GDScriptLanguage::get_singleton()->get_extension()) { + Ref<GDScriptParserRef> ref = get_parser_for(path); + if (ref.is_null()) { + push_error(vformat(R"(Could not find script for class "%s".)", p_class_name), p_source); + type.type_source = GDScriptParser::DataType::UNDETECTED; + type.kind = GDScriptParser::DataType::VARIANT; + return type; + } + + Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); + if (err) { + push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source); + type.type_source = GDScriptParser::DataType::UNDETECTED; + type.kind = GDScriptParser::DataType::VARIANT; + return type; + } + + type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + type.kind = GDScriptParser::DataType::CLASS; + type.builtin_type = Variant::OBJECT; + type.native_type = ScriptServer::get_global_class_native_base(p_class_name); + type.class_type = ref->get_parser()->head; + type.script_path = ref->get_parser()->script_path; + type.is_constant = true; + type.is_meta_type = true; return type; - } - - Error err = ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); - if (err) { - push_error(vformat(R"(Could not resolve class "%s", because of a parser error.)", p_class_name), p_source); - type.type_source = GDScriptParser::DataType::UNDETECTED; - type.kind = GDScriptParser::DataType::VARIANT; + } else { + type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + type.kind = GDScriptParser::DataType::SCRIPT; + type.builtin_type = Variant::OBJECT; + type.native_type = ScriptServer::get_global_class_native_base(p_class_name); + type.script_type = ResourceLoader::load(path, "Script"); + type.script_path = path; + type.is_constant = true; + type.is_meta_type = true; return type; } - - type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - type.kind = GDScriptParser::DataType::CLASS; - type.builtin_type = Variant::OBJECT; - type.native_type = ScriptServer::get_global_class_native_base(p_class_name); - type.class_type = ref->get_parser()->head; - type.script_path = ref->get_parser()->script_path; - type.is_constant = true; - type.is_meta_type = true; - return type; } void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base) { @@ -3189,7 +3215,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) { p_preload->resolved_path = parser->script_path.get_base_dir().path_join(p_preload->resolved_path); } p_preload->resolved_path = p_preload->resolved_path.simplify_path(); - if (!FileAccess::exists(p_preload->resolved_path)) { + if (!ResourceLoader::exists(p_preload->resolved_path)) { push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path); } else { // TODO: Don't load if validating: use completion cache. @@ -3808,7 +3834,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo Ref<Script> base_script = p_base_type.script_type; - while (base_script.is_valid() && base_script->is_valid()) { + while (base_script.is_valid() && base_script->has_method(function_name)) { MethodInfo info = base_script->get_method_info(function_name); if (!(info == MethodInfo())) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 888cd782fb..d8a06a8663 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3758,6 +3758,33 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node return false; } break; + case GDScriptParser::DataType::CLASS: + // Can assume type is a global GDScript class. + if (!ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { + push_error(R"(Exported script type must extend Resource.)"); + return false; + } + variable->export_info.type = Variant::OBJECT; + variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; + variable->export_info.hint_string = export_type.class_type->identifier->name; + break; + case GDScriptParser::DataType::SCRIPT: { + StringName class_name; + if (export_type.script_type != nullptr && export_type.script_type.is_valid()) { + class_name = export_type.script_type->get_language()->get_global_class_name(export_type.script_type->get_path()); + } + if (class_name == StringName()) { + Ref<Script> script = ResourceLoader::load(export_type.script_path, SNAME("Script")); + if (script.is_valid()) { + class_name = script->get_language()->get_global_class_name(export_type.script_path); + } + } + if (class_name != StringName() && ClassDB::is_parent_class(ScriptServer::get_global_class_native_base(class_name), SNAME("Resource"))) { + variable->export_info.type = Variant::OBJECT; + variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; + variable->export_info.hint_string = class_name; + } + } break; case GDScriptParser::DataType::ENUM: { variable->export_info.type = Variant::INT; variable->export_info.hint = PROPERTY_HINT_ENUM; diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub index 71f3ba58d9..5f111165fd 100644 --- a/modules/gltf/SCsub +++ b/modules/gltf/SCsub @@ -7,7 +7,7 @@ env_gltf = env_modules.Clone() # Godot source files env_gltf.add_source_files(env.modules_sources, "*.cpp") -env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp") env_gltf.add_source_files(env.modules_sources, "structures/*.cpp") +SConscript("extensions/SCsub") if env["tools"]: env_gltf.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index d2a9022445..936794976d 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GLTFDocumentExtension" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> + [GLTFDocument] extension class. </brief_description> <description> + Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export. </description> <tutorials> </tutorials> @@ -28,6 +30,12 @@ <description> </description> </method> + <method name="_get_supported_extensions" qualifiers="virtual"> + <return type="PackedStringArray" /> + <description> + Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded. + </description> + </method> <method name="_import_node" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index e933e6046a..4d1aa89ac9 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -1,10 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GLTFNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> + GLTF node class. </brief_description> <description> + Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes). </description> <tutorials> + <link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link> </tutorials> <members> <member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1"> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 1dbd89aed8..6c2f488c1c 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -7,6 +7,14 @@ <tutorials> </tutorials> <methods> + <method name="add_used_extension"> + <return type="void" /> + <param index="0" name="extension_name" type="String" /> + <param index="1" name="required" type="bool" /> + <description> + Appends an extension to the list of extensions used by this GLTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically. + </description> + </method> <method name="get_accessors"> <return type="GLTFAccessor[]" /> <description> diff --git a/modules/gltf/extensions/SCsub b/modules/gltf/extensions/SCsub new file mode 100644 index 0000000000..ad214bb79c --- /dev/null +++ b/modules/gltf/extensions/SCsub @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_gltf = env_modules.Clone() + +# Godot source files +env_gltf.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h index c20c87f798..9ee2397968 100644 --- a/modules/gltf/gltf_defines.h +++ b/modules/gltf/gltf_defines.h @@ -66,9 +66,9 @@ using GLTFBufferIndex = int; using GLTFBufferViewIndex = int; using GLTFCameraIndex = int; using GLTFImageIndex = int; +using GLTFLightIndex = int; using GLTFMaterialIndex = int; using GLTFMeshIndex = int; -using GLTFLightIndex = int; using GLTFNodeIndex = int; using GLTFSkeletonIndex = int; using GLTFSkinIndex = int; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index f5730e7137..8d2e37be3a 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -191,14 +191,14 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { return Error::FAILED; } - /* STEP SERIALIZE SCENE */ + /* STEP SERIALIZE LIGHTS */ err = _serialize_lights(state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE EXTENSIONS */ - err = _serialize_extensions(state); + err = _serialize_gltf_extensions(state); if (err != OK) { return Error::FAILED; } @@ -219,9 +219,9 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { return OK; } -Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const { - Array extensions_used; - Array extensions_required; +Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> state) const { + Vector<String> extensions_used = state->extensions_used; + Vector<String> extensions_required = state->extensions_required; if (!state->lights.is_empty()) { extensions_used.push_back("KHR_lights_punctual"); } @@ -230,9 +230,11 @@ Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const { extensions_required.push_back("KHR_texture_transform"); } if (!extensions_used.is_empty()) { + extensions_used.sort(); state->json["extensionsUsed"] = extensions_used; } if (!extensions_required.is_empty()) { + extensions_required.sort(); state->json["extensionsRequired"] = extensions_required; } return OK; @@ -401,47 +403,47 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { Array nodes; for (int i = 0; i < state->nodes.size(); i++) { Dictionary node; - Ref<GLTFNode> n = state->nodes[i]; + Ref<GLTFNode> gltf_node = state->nodes[i]; Dictionary extensions; node["extensions"] = extensions; - if (!n->get_name().is_empty()) { - node["name"] = n->get_name(); + if (!gltf_node->get_name().is_empty()) { + node["name"] = gltf_node->get_name(); } - if (n->camera != -1) { - node["camera"] = n->camera; + if (gltf_node->camera != -1) { + node["camera"] = gltf_node->camera; } - if (n->light != -1) { + if (gltf_node->light != -1) { Dictionary lights_punctual; extensions["KHR_lights_punctual"] = lights_punctual; - lights_punctual["light"] = n->light; + lights_punctual["light"] = gltf_node->light; } - if (n->mesh != -1) { - node["mesh"] = n->mesh; + if (gltf_node->mesh != -1) { + node["mesh"] = gltf_node->mesh; } - if (n->skin != -1) { - node["skin"] = n->skin; + if (gltf_node->skin != -1) { + node["skin"] = gltf_node->skin; } - if (n->skeleton != -1 && n->skin < 0) { + if (gltf_node->skeleton != -1 && gltf_node->skin < 0) { } - if (n->xform != Transform3D()) { - node["matrix"] = _xform_to_array(n->xform); + if (gltf_node->xform != Transform3D()) { + node["matrix"] = _xform_to_array(gltf_node->xform); } - if (!n->rotation.is_equal_approx(Quaternion())) { - node["rotation"] = _quaternion_to_array(n->rotation); + if (!gltf_node->rotation.is_equal_approx(Quaternion())) { + node["rotation"] = _quaternion_to_array(gltf_node->rotation); } - if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { - node["scale"] = _vec3_to_arr(n->scale); + if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { + node["scale"] = _vec3_to_arr(gltf_node->scale); } - if (!n->position.is_zero_approx()) { - node["translation"] = _vec3_to_arr(n->position); + if (!gltf_node->position.is_zero_approx()) { + node["translation"] = _vec3_to_arr(gltf_node->position); } - if (n->children.size()) { + if (gltf_node->children.size()) { Array children; - for (int j = 0; j < n->children.size(); j++) { - children.push_back(n->children[j]); + for (int j = 0; j < gltf_node->children.size(); j++) { + children.push_back(gltf_node->children[j]); } node["children"] = children; } @@ -450,7 +452,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; ERR_CONTINUE(ext.is_null()); ERR_CONTINUE(!state->scene_nodes.find(i)); - Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]); + Error err = ext->export_node(state, gltf_node, node, state->scene_nodes[i]); ERR_CONTINUE(err != OK); } @@ -5046,7 +5048,7 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta return mi; } -Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) { +Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr); @@ -5102,6 +5104,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeInde return spatial; } + void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { bool retflag = true; _check_visibility(p_current, retflag); @@ -6916,12 +6919,32 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) { ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR); - if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) { - Array extensions_required = state->json["extensionsRequired"]; - if (extensions_required.find("KHR_draco_mesh_compression") != -1) { - ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported."); - return ERR_UNAVAILABLE; + if (state->json.has("extensionsUsed")) { + Vector<String> ext_array = state->json["extensionsUsed"]; + state->extensions_used = ext_array; + } + if (state->json.has("extensionsRequired")) { + Vector<String> ext_array = state->json["extensionsRequired"]; + state->extensions_required = ext_array; + } + HashSet<String> supported_extensions; + supported_extensions.insert("KHR_lights_punctual"); + supported_extensions.insert("KHR_materials_pbrSpecularGlossiness"); + supported_extensions.insert("KHR_texture_transform"); + for (int ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + Vector<String> ext_supported_extensions = ext->get_supported_extensions(); + for (int i = 0; i < ext_supported_extensions.size(); ++i) { + supported_extensions.insert(ext_supported_extensions[i]); } } - return OK; + Error ret = Error::OK; + for (int i = 0; i < state->extensions_required.size(); i++) { + if (!supported_extensions.has(state->extensions_required[i])) { + ERR_PRINT("GLTF: Can't import file '" + state->filename + "', required extension '" + String(state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?"); + ret = ERR_UNAVAILABLE; + } + } + return ret; } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 36a2f94a4e..750d3d403e 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -188,7 +188,7 @@ private: const GLTFNodeIndex bone_index); ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index); Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index); - Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Light3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index); Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index); void _assign_scene_names(Ref<GLTFState> state); template <class T> @@ -265,7 +265,7 @@ private: Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material); Error _serialize_version(Ref<GLTFState> state); Error _serialize_file(Ref<GLTFState> state, const String p_path); - Error _serialize_extensions(Ref<GLTFState> state) const; + Error _serialize_gltf_extensions(Ref<GLTFState> state) const; public: // https://www.itu.int/rec/R-REC-BT.601 diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp index d0bd7651e0..3b952f8246 100644 --- a/modules/gltf/gltf_document_extension.cpp +++ b/modules/gltf/gltf_document_extension.cpp @@ -31,6 +31,7 @@ #include "gltf_document_extension.h" void GLTFDocumentExtension::_bind_methods() { + GDVIRTUAL_BIND(_get_supported_extensions); GDVIRTUAL_BIND(_import_preflight, "state"); GDVIRTUAL_BIND(_import_post_parse, "state"); GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node"); @@ -40,6 +41,12 @@ void GLTFDocumentExtension::_bind_methods() { GDVIRTUAL_BIND(_export_post, "state"); } +Vector<String> GLTFDocumentExtension::get_supported_extensions() { + Vector<String> ret; + GDVIRTUAL_CALL(_get_supported_extensions, ret); + return ret; +} + Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) { ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h index 0ef9109584..d4bb3993dc 100644 --- a/modules/gltf/gltf_document_extension.h +++ b/modules/gltf/gltf_document_extension.h @@ -41,6 +41,7 @@ protected: static void _bind_methods(); public: + virtual Vector<String> get_supported_extensions(); virtual Error import_preflight(Ref<GLTFState> p_state); virtual Error import_post_parse(Ref<GLTFState> p_state); virtual Error export_post(Ref<GLTFState> p_state); @@ -48,6 +49,7 @@ public: virtual Error export_preflight(Node *p_state); virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); + GDVIRTUAL0R(Vector<String>, _get_supported_extensions); GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>); GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>); GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 85bac446cc..a23fb39503 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -31,6 +31,7 @@ #include "gltf_state.h" void GLTFState::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension); ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json); ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json); ClassDB::bind_method(D_METHOD("get_major_version"), &GLTFState::get_major_version); @@ -112,6 +113,17 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>> } +void GLTFState::add_used_extension(const String &p_extension_name, bool p_required) { + if (!extensions_used.has(p_extension_name)) { + extensions_used.push_back(p_extension_name); + } + if (p_required) { + if (!extensions_required.has(p_extension_name)) { + extensions_required.push_back(p_extension_name); + } + } +} + Dictionary GLTFState::get_json() { return json; } diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 6b2d1ca228..791431f376 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -78,6 +78,8 @@ class GLTFState : public Resource { Vector<int> root_nodes; Vector<Ref<GLTFTexture>> textures; Vector<Ref<Texture2D>> images; + Vector<String> extensions_used; + Vector<String> extensions_required; Vector<Ref<GLTFSkin>> skins; Vector<Ref<GLTFCamera>> cameras; @@ -97,6 +99,8 @@ protected: static void _bind_methods(); public: + void add_used_extension(const String &p_extension, bool p_required = false); + Dictionary get_json(); void set_json(Dictionary p_json); diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index e7c6fe592d..6f0bc16a26 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { String header = f->get_token(); ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + "."); diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h index 1bff05129b..5f817f0ba8 100644 --- a/modules/hdr/image_loader_hdr.h +++ b/modules/hdr/image_loader_hdr.h @@ -35,7 +35,7 @@ class ImageLoaderHDR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderHDR(); }; diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp index b988bf4587..18b1a73f1c 100644 --- a/modules/hdr/register_types.cpp +++ b/modules/hdr/register_types.cpp @@ -32,14 +32,14 @@ #include "image_loader_hdr.h" -static ImageLoaderHDR *image_loader_hdr = nullptr; +static Ref<ImageLoaderHDR> image_loader_hdr; void initialize_hdr_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - image_loader_hdr = memnew(ImageLoaderHDR); + image_loader_hdr.instantiate(); ImageLoader::add_image_format_loader(image_loader_hdr); } @@ -48,5 +48,6 @@ void uninitialize_hdr_module(ModuleInitializationLevel p_level) { return; } - memdelete(image_loader_hdr); + ImageLoader::remove_image_format_loader(image_loader_hdr); + image_loader_hdr.unref(); } diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index 3e138bf633..ce20ac9060 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -104,7 +104,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p return OK; } -Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h index caa0461d05..f63db51521 100644 --- a/modules/jpg/image_loader_jpegd.h +++ b/modules/jpg/image_loader_jpegd.h @@ -35,7 +35,7 @@ class ImageLoaderJPG : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderJPG(); }; diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp index b8b48a550f..7da216bbe2 100644 --- a/modules/jpg/register_types.cpp +++ b/modules/jpg/register_types.cpp @@ -32,14 +32,14 @@ #include "image_loader_jpegd.h" -static ImageLoaderJPG *image_loader_jpg = nullptr; +static Ref<ImageLoaderJPG> image_loader_jpg; void initialize_jpg_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - image_loader_jpg = memnew(ImageLoaderJPG); + image_loader_jpg.instantiate(); ImageLoader::add_image_format_loader(image_loader_jpg); } @@ -48,5 +48,6 @@ void uninitialize_jpg_module(ModuleInitializationLevel p_level) { return; } - memdelete(image_loader_jpg); + ImageLoader::remove_image_format_loader(image_loader_jpg); + image_loader_jpg.unref(); } diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py index 6f66ce9efa..d78a9c7db8 100755 --- a/modules/mono/build_scripts/build_assemblies.py +++ b/modules/mono/build_scripts/build_assemblies.py @@ -315,6 +315,8 @@ def main(): output_dir = os.path.abspath(args.godot_output_dir) + push_nupkgs_local = os.path.abspath(args.push_nupkgs_local) if args.push_nupkgs_local else None + msbuild_tool = find_any_msbuild_tool(args.mono_prefix) if msbuild_tool is None: @@ -327,7 +329,7 @@ def main(): output_dir, args.godot_platform, args.dev_debug, - args.push_nupkgs_local, + push_nupkgs_local, args.float, ) sys.exit(exit_code) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs index efdd50098e..f31ded4d77 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -156,6 +156,10 @@ namespace Godot.SourceGenerators else if (typeKind == TypeKind.Array) { var arrayType = (IArrayTypeSymbol)type; + + if (arrayType.Rank != 1) + return null; + var elementType = arrayType.ElementType; switch (elementType.SpecialType) @@ -177,8 +181,8 @@ namespace Godot.SourceGenerators if (elementType.SimpleDerivesFrom(typeCache.GodotObjectType)) return MarshalType.GodotObjectOrDerivedArray; - if (elementType.ContainingAssembly.Name == "GodotSharp" && - elementType.ContainingNamespace.Name == "Godot") + if (elementType.ContainingAssembly?.Name == "GodotSharp" && + elementType.ContainingNamespace?.Name == "Godot") { switch (elementType) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index 1df41a905b..eeda1042ca 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -235,6 +235,8 @@ namespace Godot.SourceGenerators .Append(signalName) .Append(";\n"); + source.Append($" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedName()}\"/>\n"); + source.Append(" public event ") .Append(signalDelegate.DelegateSymbol.FullQualifiedName()) .Append(" ") diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index ad4fce8daa..4d40724a83 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -69,51 +69,41 @@ namespace GodotTools.Build private void LoadIssuesFromFile(string csvFile) { - using (var file = new Godot.File()) + using var file = FileAccess.Open(csvFile, FileAccess.ModeFlags.Read); + + if (file == null) + return; + + while (!file.EofReached()) { - try - { - Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read); + string[] csvColumns = file.GetCsvLine(); - if (openError != Error.Ok) - return; + if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0])) + return; - while (!file.EofReached()) - { - string[] csvColumns = file.GetCsvLine(); - - if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0])) - return; - - if (csvColumns.Length != 7) - { - GD.PushError($"Expected 7 columns, got {csvColumns.Length}"); - continue; - } - - var issue = new BuildIssue - { - Warning = csvColumns[0] == "warning", - File = csvColumns[1], - Line = int.Parse(csvColumns[2]), - Column = int.Parse(csvColumns[3]), - Code = csvColumns[4], - Message = csvColumns[5], - ProjectFile = csvColumns[6] - }; - - if (issue.Warning) - WarningCount += 1; - else - ErrorCount += 1; - - _issues.Add(issue); - } - } - finally + if (csvColumns.Length != 7) { - file.Close(); // Disposing it is not enough. We need to call Close() + GD.PushError($"Expected 7 columns, got {csvColumns.Length}"); + continue; } + + var issue = new BuildIssue + { + Warning = csvColumns[0] == "warning", + File = csvColumns[1], + Line = int.Parse(csvColumns[2]), + Column = int.Parse(csvColumns[3]), + Code = csvColumns[4], + Message = csvColumns[5], + ProjectFile = csvColumns[6] + }; + + if (issue.Warning) + WarningCount += 1; + else + ErrorCount += 1; + + _issues.Add(issue); } } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index c27bb959fe..95a44d3b7e 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -2229,6 +2229,35 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf // Generate signal { + p_output.append(MEMBER_BEGIN "/// <summary>\n"); + p_output.append(INDENT1 "/// "); + p_output.append("Represents the method that handles the "); + p_output.append("<see cref=\"" BINDINGS_NAMESPACE "." + p_itype.proxy_name + "." + p_isignal.proxy_name + "\"/>"); + p_output.append(" event of a "); + p_output.append("<see cref=\"" BINDINGS_NAMESPACE "." + p_itype.proxy_name + "\"/>"); + p_output.append(" class.\n"); + p_output.append(INDENT1 "/// </summary>"); + + if (p_isignal.is_deprecated) { + if (p_isignal.deprecation_message.is_empty()) { + WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'."); + } + + p_output.append(MEMBER_BEGIN "[Obsolete(\""); + p_output.append(p_isignal.deprecation_message); + p_output.append("\")]"); + } + + String delegate_name = p_isignal.proxy_name; + delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler + + // Generate delegate + p_output.append(MEMBER_BEGIN "public delegate void "); + p_output.append(delegate_name); + p_output.append("("); + p_output.append(arguments_sig); + p_output.append(");\n"); + if (p_isignal.method_doc && p_isignal.method_doc->description.size()) { String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype); Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); @@ -2247,25 +2276,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf } if (p_isignal.is_deprecated) { - if (p_isignal.deprecation_message.is_empty()) { - WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'."); - } - p_output.append(MEMBER_BEGIN "[Obsolete(\""); p_output.append(p_isignal.deprecation_message); p_output.append("\")]"); } - String delegate_name = p_isignal.proxy_name; - delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler - - // Generate delegate - p_output.append(MEMBER_BEGIN "public delegate void "); - p_output.append(delegate_name); - p_output.append("("); - p_output.append(arguments_sig); - p_output.append(");\n"); - // TODO: // Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded? // If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here. diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 6f42ad6916..91392c8f79 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -152,7 +152,7 @@ bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line, } void godot_icall_Internal_EditorNodeShowScriptScreen() { - EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT); + EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT); } void godot_icall_Internal_EditorRunPlay() { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 44f951e314..d77baab24b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -1245,12 +1245,12 @@ namespace Godot /// <summary> /// If the string is a path, this concatenates <paramref name="file"/> /// at the end of the string as a subpath. - /// E.g. <c>"this/is".PlusFile("path") == "this/is/path"</c>. + /// E.g. <c>"this/is".PathJoin("path") == "this/is/path"</c>. /// </summary> /// <param name="instance">The path that will be concatenated.</param> /// <param name="file">File name to concatenate with the path.</param> /// <returns>The concatenated path with the given file name.</returns> - public static string PlusFile(this string instance, string file) + public static string PathJoin(this string instance, string file) { if (instance.Length > 0 && instance[instance.Length - 1] == '/') return instance + file; diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp index d46972ffb6..9d28feef09 100644 --- a/modules/multiplayer/multiplayer_spawner.cpp +++ b/modules/multiplayer/multiplayer_spawner.cpp @@ -86,6 +86,23 @@ void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const { } } #endif + +PackedStringArray MultiplayerSpawner::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); + + if (spawn_path.is_empty() || !has_node(spawn_path)) { + warnings.push_back(RTR("A valid NodePath must be set in the \"Spawn Path\" property in order for MultiplayerSpawner to be able to spawn Nodes.")); + } + bool has_scenes = get_spawnable_scene_count() > 0; + // Can't check if method is overriden in placeholder scripts. + bool has_placeholder_script = get_script_instance() && get_script_instance()->is_placeholder(); + if (!has_scenes && !GDVIRTUAL_IS_OVERRIDDEN(_spawn_custom) && !has_placeholder_script) { + warnings.push_back(RTR("A list of PackedScenes must be set in the \"Auto Spawn List\" property in order for MultiplayerSpawner to automatically spawn them remotely when added as child of \"spawn_path\".")); + warnings.push_back(RTR("Alternatively, a Script implementing the function \"_spawn_custom\" must be set for this MultiplayerSpawner, and \"spawn\" must be called explicitly in code.")); + } + return warnings; +} + void MultiplayerSpawner::add_spawnable_scene(const String &p_path) { SpawnableScene sc; sc.path = p_path; @@ -94,13 +111,16 @@ void MultiplayerSpawner::add_spawnable_scene(const String &p_path) { } spawnable_scenes.push_back(sc); } + int MultiplayerSpawner::get_spawnable_scene_count() const { return spawnable_scenes.size(); } + String MultiplayerSpawner::get_spawnable_scene(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, (int)spawnable_scenes.size(), ""); return spawnable_scenes[p_idx].path; } + void MultiplayerSpawner::clear_spawnable_scenes() { spawnable_scenes.clear(); } diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h index fc3befc2d4..587c99efd1 100644 --- a/modules/multiplayer/multiplayer_spawner.h +++ b/modules/multiplayer/multiplayer_spawner.h @@ -91,6 +91,8 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; #endif public: + PackedStringArray get_configuration_warnings() const override; + Node *get_spawn_node() const { return spawn_node.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)) : nullptr; } diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp index eee1495c14..2c3ebccaeb 100644 --- a/modules/multiplayer/multiplayer_synchronizer.cpp +++ b/modules/multiplayer/multiplayer_synchronizer.cpp @@ -94,6 +94,16 @@ void MultiplayerSynchronizer::_update_process() { } } +PackedStringArray MultiplayerSynchronizer::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); + + if (root_path.is_empty() || !has_node(root_path)) { + warnings.push_back(RTR("A valid NodePath must be set in the \"Root Path\" property in order for MultiplayerSynchronizer to be able to synchronize properties.")); + } + + return warnings; +} + Error MultiplayerSynchronizer::get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs) { ERR_FAIL_COND_V(!p_obj, ERR_INVALID_PARAMETER); r_variant.resize(p_properties.size()); diff --git a/modules/multiplayer/multiplayer_synchronizer.h b/modules/multiplayer/multiplayer_synchronizer.h index e84d41db86..f10a95a1d4 100644 --- a/modules/multiplayer/multiplayer_synchronizer.h +++ b/modules/multiplayer/multiplayer_synchronizer.h @@ -66,6 +66,8 @@ public: static Error get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs); static Error set_state(const List<NodePath> &p_properties, Object *p_obj, const Vector<Variant> &p_state); + PackedStringArray get_configuration_warnings() const override; + void set_replication_interval(double p_interval); double get_replication_interval() const; uint64_t get_replication_interval_msec() const; diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 92d074cb75..94095eb61c 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -1557,7 +1557,7 @@ void OpenXRAPI::end_frame() { XrCompositionLayerProjection projection_layer = { XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type nullptr, // next - layers_list.size() > 1 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags + layers_list.size() > 0 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags play_space, // space view_count, // viewCount projection_views, // views diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index cd6081f91b..f43f2784c7 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -142,7 +142,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const p_extensions->push_back("svg"); } -Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) { +Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { String svg = p_fileaccess->get_as_utf8_string(); if (p_flags & FLAG_CONVERT_COLORS) { diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index e6f73ab18f..b0b0963c15 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -43,7 +43,7 @@ public: void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map); - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) override; + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override; virtual void get_recognized_extensions(List<String> *p_extensions) const override; }; diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp index 5b4d1d31ca..323b1d652a 100644 --- a/modules/svg/register_types.cpp +++ b/modules/svg/register_types.cpp @@ -34,7 +34,7 @@ #include <thorvg.h> -static ImageLoaderSVG *image_loader_svg = nullptr; +static Ref<ImageLoaderSVG> image_loader_svg; void initialize_svg_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { @@ -45,7 +45,8 @@ void initialize_svg_module(ModuleInitializationLevel p_level) { if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) { return; } - image_loader_svg = memnew(ImageLoaderSVG); + + image_loader_svg.instantiate(); ImageLoader::add_image_format_loader(image_loader_svg); } @@ -54,9 +55,12 @@ void uninitialize_svg_module(ModuleInitializationLevel p_level) { return; } - if (!image_loader_svg) { + if (image_loader_svg.is_null()) { + // It failed to initialize so it was not added. return; } - memdelete(image_loader_svg); + + ImageLoader::remove_image_format_loader(image_loader_svg); + image_loader_svg.unref(); tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 7aebeafe70..b0f414f7f0 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -45,7 +45,6 @@ using namespace godot; // Headers for building as built-in module. #include "core/config/project_settings.h" -#include "core/core_bind.h" #include "core/error/error_macros.h" #include "core/object/worker_thread_pool.h" #include "core/string/print_string.h" @@ -53,8 +52,6 @@ using namespace godot; #include "modules/modules_enabled.gen.h" // For freetype, msdfgen. -using namespace core_bind; - #endif // Built-in ICU data. @@ -408,13 +405,12 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { if (!icu_data_loaded) { String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename; - Ref<File> f; - f.instantiate(); - if (f->open(filename, File::READ) != OK) { + Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ); + if (f.is_null()) { return false; } uint64_t len = f->get_length(); - PackedByteArray icu_data = f->get_buffer(len); + PackedByteArray icu_data = f->_get_buffer(len); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -455,16 +451,15 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { // Store data to the res file if it's available. - Ref<File> f; - f.instantiate(); - if (f->open(p_filename, File::WRITE) != OK) { + Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE); + if (f.is_null()) { return false; } PackedByteArray icu_data; icu_data.resize(U_ICUDATA_SIZE); memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); - f->store_buffer(icu_data); + f->_store_buffer(icu_data); return true; #else @@ -1940,12 +1935,12 @@ int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { fargs.flags = FT_OPEN_MEMORY; fargs.stream = &stream; - FT_Face tmp_face; + FT_Face tmp_face = nullptr; error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face); if (error == 0) { face_count = tmp_face->num_faces; + FT_Done_Face(tmp_face); } - FT_Done_Face(tmp_face); #endif } diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 4d599dbcb5..23662bf2c4 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -1039,12 +1039,12 @@ int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const { fargs.flags = FT_OPEN_MEMORY; fargs.stream = &stream; - FT_Face tmp_face; + FT_Face tmp_face = nullptr; error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face); if (error == 0) { face_count = tmp_face->num_faces; + FT_Done_Face(tmp_face); } - FT_Done_Face(tmp_face); #endif } diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 16d9bf7b93..00ba32eae1 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff return OK; } -Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index d95c5ff30b..b257ed110d 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader { static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size); public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTGA(); }; diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp index 520ed5f799..3a9d2324e7 100644 --- a/modules/tga/register_types.cpp +++ b/modules/tga/register_types.cpp @@ -32,14 +32,14 @@ #include "image_loader_tga.h" -static ImageLoaderTGA *image_loader_tga = nullptr; +static Ref<ImageLoaderTGA> image_loader_tga; void initialize_tga_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - image_loader_tga = memnew(ImageLoaderTGA); + image_loader_tga.instantiate(); ImageLoader::add_image_format_loader(image_loader_tga); } @@ -48,5 +48,6 @@ void uninitialize_tga_module(ModuleInitializationLevel p_level) { return; } - memdelete(image_loader_tga); + ImageLoader::remove_image_format_loader(image_loader_tga); + image_loader_tga.unref(); } diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 6f61251f9b..5c43bfc8b7 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -37,7 +37,7 @@ #include "thirdparty/tinyexr/tinyexr.h" -Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h index 8da2a0d4af..ab34a59da5 100644 --- a/modules/tinyexr/image_loader_tinyexr.h +++ b/modules/tinyexr/image_loader_tinyexr.h @@ -35,7 +35,7 @@ class ImageLoaderTinyEXR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTinyEXR(); }; diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp index c5897f37c3..b1a9f18e3b 100644 --- a/modules/tinyexr/register_types.cpp +++ b/modules/tinyexr/register_types.cpp @@ -33,14 +33,14 @@ #include "image_loader_tinyexr.h" #include "image_saver_tinyexr.h" -static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr; +static Ref<ImageLoaderTinyEXR> image_loader_tinyexr; void initialize_tinyexr_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - image_loader_tinyexr = memnew(ImageLoaderTinyEXR); + image_loader_tinyexr.instantiate(); ImageLoader::add_image_format_loader(image_loader_tinyexr); Image::save_exr_func = save_exr; @@ -52,7 +52,8 @@ void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) { return; } - memdelete(image_loader_tinyexr); + ImageLoader::remove_image_format_loader(image_loader_tinyexr); + image_loader_tinyexr.unref(); Image::save_exr_func = nullptr; } diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 705ab508ab..dd387db554 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -48,7 +48,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { return img; } -Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { +Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h index d868ae3f7f..0522e4ef91 100644 --- a/modules/webp/image_loader_webp.h +++ b/modules/webp/image_loader_webp.h @@ -35,7 +35,7 @@ class ImageLoaderWebP : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderWebP(); }; diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp index 29f633743e..e523f43cfe 100644 --- a/modules/webp/register_types.cpp +++ b/modules/webp/register_types.cpp @@ -33,7 +33,7 @@ #include "image_loader_webp.h" #include "resource_saver_webp.h" -static ImageLoaderWebP *image_loader_webp = nullptr; +static Ref<ImageLoaderWebP> image_loader_webp; static Ref<ResourceSaverWebP> resource_saver_webp; void initialize_webp_module(ModuleInitializationLevel p_level) { @@ -41,9 +41,10 @@ void initialize_webp_module(ModuleInitializationLevel p_level) { return; } - image_loader_webp = memnew(ImageLoaderWebP); - resource_saver_webp.instantiate(); + image_loader_webp.instantiate(); ImageLoader::add_image_format_loader(image_loader_webp); + + resource_saver_webp.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_webp); } @@ -52,7 +53,9 @@ void uninitialize_webp_module(ModuleInitializationLevel p_level) { return; } - memdelete(image_loader_webp); + ImageLoader::remove_image_format_loader(image_loader_webp); + image_loader_webp.unref(); + ResourceSaver::remove_resource_format_saver(resource_saver_webp); resource_saver_webp.unref(); } diff --git a/modules/webxr/config.py b/modules/webxr/config.py index f676ef3483..8d75e7f531 100644 --- a/modules/webxr/config.py +++ b/modules/webxr/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return not env["disable_3d"] + return env["opengl3"] and not env["disable_3d"] def configure(env): diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h index 52104895d4..34d068be3e 100644 --- a/modules/webxr/godot_webxr.h +++ b/modules/webxr/godot_webxr.h @@ -65,8 +65,7 @@ extern int godot_webxr_get_view_count(); extern int *godot_webxr_get_render_target_size(); extern float *godot_webxr_get_transform_for_eye(int p_eye); extern float *godot_webxr_get_projection_for_eye(int p_eye); -extern int godot_webxr_get_external_texture_for_eye(int p_eye); -extern void godot_webxr_commit_for_eye(int p_eye); +extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo); extern void godot_webxr_sample_controller_data(); extern int godot_webxr_get_controller_count(); diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js index c4b21defce..9b75796ee5 100644 --- a/modules/webxr/native/library_godot_webxr.js +++ b/modules/webxr/native/library_godot_webxr.js @@ -32,9 +32,6 @@ const GodotWebXR = { $GodotWebXR: { gl: null, - texture_ids: [null, null], - textures: [null, null], - session: null, space: null, frame: null, @@ -77,110 +74,6 @@ const GodotWebXR = { }, 0); }, - // Some custom WebGL code for blitting our eye textures to the - // framebuffer we get from WebXR. - shaderProgram: null, - programInfo: null, - buffer: null, - // Vertex shader source. - vsSource: ` - const vec2 scale = vec2(0.5, 0.5); - attribute vec4 aVertexPosition; - - varying highp vec2 vTextureCoord; - - void main () { - gl_Position = aVertexPosition; - vTextureCoord = aVertexPosition.xy * scale + scale; - } - `, - // Fragment shader source. - fsSource: ` - varying highp vec2 vTextureCoord; - - uniform sampler2D uSampler; - - void main() { - gl_FragColor = texture2D(uSampler, vTextureCoord); - } - `, - - initShaderProgram: (gl, vsSource, fsSource) => { - const vertexShader = GodotWebXR.loadShader(gl, gl.VERTEX_SHADER, vsSource); - const fragmentShader = GodotWebXR.loadShader(gl, gl.FRAGMENT_SHADER, fsSource); - - const shaderProgram = gl.createProgram(); - gl.attachShader(shaderProgram, vertexShader); - gl.attachShader(shaderProgram, fragmentShader); - gl.linkProgram(shaderProgram); - - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - GodotRuntime.error(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`); - return null; - } - - return shaderProgram; - }, - loadShader: (gl, type, source) => { - const shader = gl.createShader(type); - gl.shaderSource(shader, source); - gl.compileShader(shader); - - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - GodotRuntime.error(`An error occurred compiling the shader: ${gl.getShaderInfoLog(shader)}`); - gl.deleteShader(shader); - return null; - } - - return shader; - }, - initBuffer: (gl) => { - const positionBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - const positions = [ - -1.0, -1.0, - 1.0, -1.0, - -1.0, 1.0, - 1.0, 1.0, - ]; - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); - return positionBuffer; - }, - blitTexture: (gl, texture) => { - if (GodotWebXR.shaderProgram === null) { - GodotWebXR.shaderProgram = GodotWebXR.initShaderProgram(gl, GodotWebXR.vsSource, GodotWebXR.fsSource); - GodotWebXR.programInfo = { - program: GodotWebXR.shaderProgram, - attribLocations: { - vertexPosition: gl.getAttribLocation(GodotWebXR.shaderProgram, 'aVertexPosition'), - }, - uniformLocations: { - uSampler: gl.getUniformLocation(GodotWebXR.shaderProgram, 'uSampler'), - }, - }; - GodotWebXR.buffer = GodotWebXR.initBuffer(gl); - } - - const orig_program = gl.getParameter(gl.CURRENT_PROGRAM); - gl.useProgram(GodotWebXR.shaderProgram); - - gl.bindBuffer(gl.ARRAY_BUFFER, GodotWebXR.buffer); - gl.vertexAttribPointer(GodotWebXR.programInfo.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0); - gl.enableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.uniform1i(GodotWebXR.programInfo.uniformLocations.uSampler, 0); - - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - - // Restore state. - gl.bindTexture(gl.TEXTURE_2D, null); - gl.disableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - gl.useProgram(orig_program); - }, - // Holds the controllers list between function calls. controllers: [], @@ -370,22 +263,6 @@ const GodotWebXR = { .catch((e) => { }); } - // Clean-up the textures we allocated for each view. - const gl = GodotWebXR.gl; - for (let i = 0; i < GodotWebXR.textures.length; i++) { - const texture = GodotWebXR.textures[i]; - if (texture !== null) { - gl.deleteTexture(texture); - } - GodotWebXR.textures[i] = null; - - const texture_id = GodotWebXR.texture_ids[i]; - if (texture_id !== null) { - GL.textures[texture_id] = null; - } - GodotWebXR.texture_ids[i] = null; - } - GodotWebXR.session = null; GodotWebXR.space = null; GodotWebXR.frame = null; @@ -460,50 +337,9 @@ const GodotWebXR = { return buf; }, - godot_webxr_get_external_texture_for_eye__proxy: 'sync', - godot_webxr_get_external_texture_for_eye__sig: 'ii', - godot_webxr_get_external_texture_for_eye: function (p_eye) { - if (!GodotWebXR.session) { - return 0; - } - - const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0; - if (GodotWebXR.texture_ids[view_index]) { - return GodotWebXR.texture_ids[view_index]; - } - - // Check pose separately and after returning the cached texture id, - // because we won't get a pose in some cases if we lose tracking, and - // we don't want to return 0 just because tracking was lost. - if (!GodotWebXR.pose) { - return 0; - } - - const glLayer = GodotWebXR.session.renderState.baseLayer; - const view = GodotWebXR.pose.views[view_index]; - const viewport = glLayer.getViewport(view); - const gl = GodotWebXR.gl; - - const texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, viewport.width, viewport.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.bindTexture(gl.TEXTURE_2D, null); - - const texture_id = GL.getNewId(GL.textures); - GL.textures[texture_id] = texture; - GodotWebXR.textures[view_index] = texture; - GodotWebXR.texture_ids[view_index] = texture_id; - return texture_id; - }, - godot_webxr_commit_for_eye__proxy: 'sync', - godot_webxr_commit_for_eye__sig: 'vi', - godot_webxr_commit_for_eye: function (p_eye) { + godot_webxr_commit_for_eye__sig: 'vii', + godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) { if (!GodotWebXR.session || !GodotWebXR.pose) { return; } @@ -514,18 +350,29 @@ const GodotWebXR = { const viewport = glLayer.getViewport(view); const gl = GodotWebXR.gl; + const framebuffer = GL.framebuffers[p_destination_fbo]; + const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); - const orig_viewport = gl.getParameter(gl.VIEWPORT); + const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING); + const orig_read_buffer = gl.getParameter(gl.READ_BUFFER); + const orig_draw_framebuffer = gl.getParameter(gl.DRAW_FRAMEBUFFER_BINDING); - // Bind to WebXR's framebuffer. - gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer); - gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); + // Copy from Godot render target into framebuffer from WebXR. + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer); + gl.readBuffer(gl.COLOR_ATTACHMENT0); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer); - GodotWebXR.blitTexture(gl, GodotWebXR.textures[view_index]); + // Flip Y upside down on destination. + gl.blitFramebuffer(0, 0, viewport.width, viewport.height, + viewport.x, viewport.height, viewport.width, viewport.y, + gl.COLOR_BUFFER_BIT, gl.NEAREST); // Restore state. gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer); - gl.viewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, orig_read_framebuffer); + gl.readBuffer(orig_read_buffer); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, orig_draw_framebuffer); }, godot_webxr_sample_controller_data__proxy: 'sync', diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 7d97dbfa0b..d0c7484aa1 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -34,9 +34,11 @@ #include "core/input/input.h" #include "core/os/os.h" +#include "drivers/gles3/storage/texture_storage.h" #include "emscripten.h" #include "godot_webxr.h" #include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/rendering_server_globals.h" #include <stdlib.h> @@ -232,6 +234,8 @@ bool WebXRInterfaceJS::initialize() { } // we must create a tracker for our head + head_transform.basis = Basis(); + head_transform.origin = Vector3(); head_tracker.instantiate(); head_tracker->set_tracker_type(XRServer::TRACKER_HEAD); head_tracker->set_tracker_name("head"); @@ -334,15 +338,17 @@ Transform3D WebXRInterfaceJS::get_camera_transform() { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, transform_for_eye); - float *js_matrix = godot_webxr_get_transform_for_eye(0); - if (!initialized || js_matrix == nullptr) { - return transform_for_eye; - } + if (initialized) { + float world_scale = xr_server->get_world_scale(); - transform_for_eye = _js_matrix_to_transform(js_matrix); - free(js_matrix); + // just scale our origin point of our transform + Transform3D _head_transform = head_transform; + _head_transform.origin *= world_scale; + + transform_for_eye = (xr_server->get_reference_frame()) * _head_transform; + } - return xr_server->get_reference_frame() * transform_for_eye; + return transform_for_eye; }; Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { @@ -360,6 +366,14 @@ Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Tran transform_for_eye = _js_matrix_to_transform(js_matrix); free(js_matrix); + float world_scale = xr_server->get_world_scale(); + // Scale only the center point of our eye transform, so we don't scale the + // distance between the eyes. + Transform3D _head_transform = head_transform; + transform_for_eye.origin -= _head_transform.origin; + _head_transform.origin *= world_scale; + transform_for_eye.origin += _head_transform.origin; + return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye; }; @@ -394,29 +408,33 @@ Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c return blit_to_screen; } - // @todo Refactor this to be based on "views" rather than "eyes". - godot_webxr_commit_for_eye(1); - if (godot_webxr_get_view_count() > 1) { - godot_webxr_commit_for_eye(2); + GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage); + if (!texture_storage) { + return blit_to_screen; } + GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target); + + // @todo Support multiple eyes! + godot_webxr_commit_for_eye(1, rt->fbo); + return blit_to_screen; }; void WebXRInterfaceJS::process() { if (initialized) { - godot_webxr_sample_controller_data(); - + // Get the "head" position. + float *js_matrix = godot_webxr_get_transform_for_eye(0); + if (js_matrix != nullptr) { + head_transform = _js_matrix_to_transform(js_matrix); + free(js_matrix); + } if (head_tracker.is_valid()) { - // TODO set default pose to our head location (i.e. get_camera_transform without world scale and reference frame applied) - // head_tracker->set_pose("default", head_transform, Vector3(), Vector3()); + head_tracker->set_pose("default", head_transform, Vector3(), Vector3()); } + godot_webxr_sample_controller_data(); int controller_count = godot_webxr_get_controller_count(); - if (controller_count == 0) { - return; - } - for (int i = 0; i < controller_count; i++) { _update_tracker(i); } diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index dbe89dad83..319adc2ac9 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -45,6 +45,7 @@ class WebXRInterfaceJS : public WebXRInterface { private: bool initialized; Ref<XRPositionalTracker> head_tracker; + Transform3D head_transform; String session_mode; String required_features; diff --git a/platform/android/detect.py b/platform/android/detect.py index 1d9bcdd932..a31bba745f 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -47,9 +47,6 @@ def get_flags(): return [ ("arch", "arm64"), # Default for convenience. ("tools", False), - # Benefits of LTO for Android (size, performance) haven't been clearly established yet. - # So for now we override the default value which may be set when using `production=yes`. - ("lto", "none"), ] @@ -136,6 +133,10 @@ def configure(env): env.Append(CPPFLAGS=["-UNDEBUG"]) # LTO + + if env["lto"] == "auto": # LTO benefits for Android (size, performance) haven't been clearly established yet. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index e5656bd00b..366bd1c48c 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1669,14 +1669,7 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp } void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "opengl3") { - r_features->push_back("etc"); - } - // FIXME: Review what texture formats are used for Vulkan. - if (driver == "vulkan") { - r_features->push_back("etc2"); - } + r_features->push_back("etc2"); Vector<String> abis = get_enabled_abis(p_preset); for (int i = 0; i < abis.size(); ++i) { diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 8d370a31a4..2f53942f76 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -189,9 +189,7 @@ String bool_to_string(bool v) { } String _get_gles_tag() { - bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" && - !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2"); - return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : ""; + return " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n"; } String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) { diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index ace7636e6c..d6cd62e9f5 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -42,7 +42,7 @@ String FileAccessAndroid::get_path_absolute() const { return absolute_path; } -Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) { +Error FileAccessAndroid::open_internal(const String &p_path, int p_mode_flags) { _close(); path_src = p_path; diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index 8d7ade8ead..55f8fbe0f4 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -49,7 +49,7 @@ class FileAccessAndroid : public FileAccess { public: static AAssetManager *asset_manager; - virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file + 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 /// returns the path for the current open file diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index 56561cb616..c2ee3389ae 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -61,7 +61,7 @@ String FileAccessFilesystemJAndroid::get_path_absolute() const { return absolute_path; } -Error FileAccessFilesystemJAndroid::_open(const String &p_path, int p_mode_flags) { +Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mode_flags) { if (is_open()) { _close(); } diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index 76d7db6e3a..815ab36516 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -60,7 +60,7 @@ class FileAccessFilesystemJAndroid : public FileAccess { void _set_eof(bool eof); public: - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + 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 /// returns the path for the current open file diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index a75c69484c..92e5e59496 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -274,11 +274,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC return false; } - final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name"); - if (videoDriver.equals("vulkan")) { - mRenderView = new GodotVulkanRenderView(activity, this); - } else { + final String renderer = GodotLib.getGlobal("rendering/renderer/rendering_method"); + if (renderer.equals("gl_compatibility")) { mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl); + } else { + mRenderView = new GodotVulkanRenderView(activity, this); } View view = mRenderView.getView(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 142dc54c45..4469c7a0f7 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -44,6 +44,7 @@ #include "net_socket_android.h" #include <dlfcn.h> +#include <sys/system_properties.h> #include "java_godot_io_wrapper.h" #include "java_godot_wrapper.h" @@ -175,6 +176,79 @@ String OS_Android::get_name() const { return "Android"; } +String OS_Android::get_system_property(const char *key) const { + static String value; + char value_str[PROP_VALUE_MAX]; + if (__system_property_get(key, value_str)) { + value = String(value_str); + } + return value; +} + +String OS_Android::get_distribution_name() const { + if (!get_system_property("ro.havoc.version").is_empty()) { + return "Havoc OS"; + } else if (!get_system_property("org.pex.version").is_empty()) { // Putting before "Pixel Experience", because it's derivating from it. + return "Pixel Extended"; + } else if (!get_system_property("org.pixelexperience.version").is_empty()) { + return "Pixel Experience"; + } else if (!get_system_property("ro.potato.version").is_empty()) { + return "POSP"; + } else if (!get_system_property("ro.xtended.version").is_empty()) { + return "Project-Xtended"; + } else if (!get_system_property("org.evolution.version").is_empty()) { + return "Evolution X"; + } else if (!get_system_property("ro.corvus.version").is_empty()) { + return "Corvus-Q"; + } else if (!get_system_property("ro.pa.version").is_empty()) { + return "Paranoid Android"; + } else if (!get_system_property("ro.crdroid.version").is_empty()) { + return "crDroid Android"; + } else if (!get_system_property("ro.syberia.version").is_empty()) { + return "Syberia Project"; + } else if (!get_system_property("ro.arrow.version").is_empty()) { + return "ArrowOS"; + } else if (!get_system_property("ro.lineage.version").is_empty()) { // Putting LineageOS last, just in case any derivative writes to "ro.lineage.version". + return "LineageOS"; + } + + if (!get_system_property("ro.modversion").is_empty()) { // Handles other Android custom ROMs. + return vformat("%s %s", get_name(), "Custom ROM"); + } + + // Handles stock Android. + return get_name(); +} + +String OS_Android::get_version() const { + const Vector<const char *> roms = { "ro.havoc.version", "org.pex.version", "org.pixelexperience.version", + "ro.potato.version", "ro.xtended.version", "org.evolution.version", "ro.corvus.version", "ro.pa.version", + "ro.crdroid.version", "ro.syberia.version", "ro.arrow.version", "ro.lineage.version" }; + for (int i = 0; i < roms.size(); i++) { + static String rom_version = get_system_property(roms[i]); + if (!rom_version.is_empty()) { + return rom_version; + } + } + + static String mod_version = get_system_property("ro.modversion"); // Handles other Android custom ROMs. + if (!mod_version.is_empty()) { + return mod_version; + } + + // Handles stock Android. + static String sdk_version = get_system_property("ro.build.version.sdk_int"); + static String build = get_system_property("ro.build.version.incremental"); + if (!sdk_version.is_empty()) { + if (!build.is_empty()) { + return vformat("%s.%s", sdk_version, build); + } + return sdk_version; + } + + return ""; +} + MainLoop *OS_Android::get_main_loop() const { return main_loop; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 96c06d715c..d6546a3507 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -65,6 +65,8 @@ private: GodotJavaWrapper *godot_java = nullptr; GodotIOJavaWrapper *godot_io_java = nullptr; + String get_system_property(const char *key) const; + public: static const char *ANDROID_EXEC_PATH; @@ -93,6 +95,8 @@ public: virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual MainLoop *get_main_loop() const override; void main_loop_begin(); diff --git a/platform/ios/detect.py b/platform/ios/detect.py index ed7e714c4e..d5e6ee4b46 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -39,9 +39,6 @@ def get_flags(): ("arch", "arm64"), # Default for convenience. ("tools", False), ("use_volk", False), - # Disable by default even if production is set, as it makes linking in Xcode - # on exports very slow and that's not what most users expect. - ("lto", "none"), ] @@ -73,7 +70,11 @@ def configure(env): env.Append(CCFLAGS=["-gdwarf-2", "-O0"]) env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)]) - # LTO + ## LTO + + if env["lto"] == "auto": # Disable by default as it makes linking in Xcode very slow. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) diff --git a/platform/ios/display_layer.mm b/platform/ios/display_layer.mm index 7c83494768..74c760ae9a 100644 --- a/platform/ios/display_layer.mm +++ b/platform/ios/display_layer.mm @@ -89,12 +89,12 @@ // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - // Create GL ES 2 context - if (GLOBAL_GET("rendering/driver/driver_name") == "opengl3") { - context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - NSLog(@"Setting up an OpenGL ES 2.0 context."); + // Create GL ES 3 context + if (GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility") { + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; + NSLog(@"Setting up an OpenGL ES 3.0 context."); if (!context) { - NSLog(@"Failed to create OpenGL ES 2.0 context!"); + NSLog(@"Failed to create OpenGL ES 3.0 context!"); return; } } diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 74d6bc2e97..d3a0f38463 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -62,7 +62,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode // 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 == "opengl_es") { + if (rendering_driver == "opengl3") { bool gl_initialization_error = false; // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? @@ -163,7 +163,7 @@ Vector<String> DisplayServerIOS::get_rendering_drivers_func() { drivers.push_back("vulkan"); #endif #if defined(GLES3_ENABLED) - drivers.push_back("opengl_es"); + drivers.push_back("opengl3"); #endif return drivers; diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 7aacb2de85..74a57dc614 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -34,7 +34,6 @@ #include "editor/editor_node.h" void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); // Vulkan and OpenGL ES 3.0 both mandate ETC2 support. r_features->push_back("etc2"); diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm index 9ed219508c..ff90c05b1d 100644 --- a/platform/ios/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -74,7 +74,7 @@ static const float earth_gravity = 9.80665; if ([driverName isEqualToString:@"vulkan"]) { layer = [GodotMetalLayer layer]; - } else if ([driverName isEqualToString:@"opengl_es"]) { + } else if ([driverName isEqualToString:@"opengl3"]) { if (@available(iOS 13, *)) { NSLog(@"OpenGL ES is deprecated on iOS 13"); } diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index 3b88f53b6a..00d91da771 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -100,6 +100,8 @@ public: virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual String get_model_name() const override; virtual Error shell_open(String p_uri) override; diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index b9d186f355..a674498620 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -240,6 +240,15 @@ String OS_IOS::get_name() const { return "iOS"; } +String OS_IOS::get_distribution_name() const { + return get_name(); +} + +String OS_IOS::get_version() const { + NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion; + return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion); +} + String OS_IOS::get_model_name() const { String model = ios->get_model(); if (model != "") { diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 36644d5f29..12d2432eea 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -171,6 +171,10 @@ def configure(env): env.Append(LINKFLAGS=["-fsanitize=memory"]) # LTO + + if env["lto"] == "auto": # Full LTO for production. + env["lto"] = "full" + if env["lto"] != "none": if env["lto"] == "thin": if not env["use_llvm"]: diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 0236e134fb..66dea6cf1b 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -397,7 +397,10 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) { if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { //flush pending motion events _flush_mouse_motion(); - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } WindowData &window = windows[window_id]; if (XGrabPointer( @@ -433,7 +436,11 @@ void DisplayServerX11::warp_mouse(const Point2i &p_position) { if (mouse_mode == MOUSE_MODE_CAPTURED) { last_mouse_pos = p_position; } else { - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } + XWarpPointer(x11_display, None, windows[window_id].x11_window, 0, 0, 0, 0, (int)p_position.x, (int)p_position.y); } @@ -3181,6 +3188,15 @@ void DisplayServerX11::_window_changed(XEvent *event) { } } +DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const { + const List<WindowID>::Element *E = popup_list.back(); + if (E) { + return E->get(); + } + + return last_focused_window; +} + void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) { static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event); } @@ -3936,7 +3952,11 @@ void DisplayServerX11::process_events() { // The X11 API requires filtering one-by-one through the motion // notify events, in order to figure out which event is the one // generated by warping the mouse pointer. - WindowID focused_window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID focused_window_id = _get_focused_window_or_popup(); + if (!windows.has(focused_window_id)) { + focused_window_id = MAIN_WINDOW_ID; + } + while (true) { if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[focused_window_id].size.width / 2 && event.xmotion.y == windows[focused_window_id].size.height / 2) { //this is likely the warp event since it was warped here diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index ea03b2328c..a5fa7613bc 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -284,6 +284,8 @@ class DisplayServerX11 : public DisplayServer { Context context = CONTEXT_ENGINE; + WindowID _get_focused_window_or_popup() const; + void _send_window_event(const WindowData &wd, WindowEvent p_event); static void _dispatch_input_events(const Ref<InputEvent> &p_event); void _dispatch_input_event(const Ref<InputEvent> &p_event); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index f0d7b6ede5..f4e94f1a91 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -50,6 +50,7 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> +#include <sys/utsname.h> #include <unistd.h> #ifdef FONTCONFIG_ENABLED @@ -205,6 +206,42 @@ String OS_LinuxBSD::get_name() const { #endif } +String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const { + static String info; + if (info.is_empty()) { + Ref<FileAccess> f = FileAccess::open("/etc/os-release", FileAccess::READ); + if (f.is_valid()) { + while (!f->eof_reached()) { + const String line = f->get_line(); + if (line.find(key) != -1) { + return line.split("=")[1].strip_edges(); + } + } + } + } + return info; +} + +String OS_LinuxBSD::get_distribution_name() const { + static String systemd_name = get_systemd_os_release_info_value("NAME"); // returns a value for systemd users, otherwise an empty string. + if (!systemd_name.is_empty()) { + return systemd_name; + } + struct utsname uts; // returns a decent value for BSD family. + uname(&uts); + return uts.sysname; +} + +String OS_LinuxBSD::get_version() const { + static String systemd_version = get_systemd_os_release_info_value("VERSION"); // returns a value for systemd users, otherwise an empty string. + if (!systemd_version.is_empty()) { + return systemd_version; + } + struct utsname uts; // returns a decent value for BSD family. + uname(&uts); + return uts.version; +} + Error OS_LinuxBSD::shell_open(String p_uri) { Error ok; int err_code; diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index d5b2321316..722d83ba19 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -67,6 +67,8 @@ class OS_LinuxBSD : public OS_Unix { MainLoop *main_loop = nullptr; + String get_systemd_os_release_info_value(const String &key) const; + protected: virtual void initialize() override; virtual void finalize() override; @@ -77,6 +79,8 @@ protected: public: virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual MainLoop *get_main_loop() const override; diff --git a/platform/macos/SCsub b/platform/macos/SCsub index bbd461fba9..7ffb80f70b 100644 --- a/platform/macos/SCsub +++ b/platform/macos/SCsub @@ -12,6 +12,7 @@ files = [ "crash_handler_macos.mm", "macos_terminal_logger.mm", "display_server_macos.mm", + "godot_button_view.mm", "godot_content_view.mm", "godot_window_delegate.mm", "godot_window.mm", diff --git a/platform/macos/detect.py b/platform/macos/detect.py index bcf4776609..834ac935d8 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -40,9 +40,6 @@ def get_flags(): return [ ("arch", detect_arch()), ("use_volk", False), - # Benefits of LTO for macOS (size, performance) haven't been clearly established yet. - # So for now we override the default value which may be set when using `production=yes`. - ("lto", "none"), ] @@ -170,6 +167,10 @@ def configure(env): env["AS"] = basecmd + "as" # LTO + + if env["lto"] == "auto": # LTO benefits for macOS (size, performance) haven't been clearly established yet. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) @@ -178,6 +179,8 @@ def configure(env): env.Append(CCFLAGS=["-flto"]) env.Append(LINKFLAGS=["-flto"]) + # Sanitizers + if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]: env.extra_suffix += ".san" env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"]) diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 769cba2de5..576e7aa9ca 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -76,6 +76,7 @@ public: id window_delegate; id window_object; id window_view; + id window_button_view; Vector<Vector2> mpath; @@ -84,6 +85,9 @@ public: Size2i min_size; Size2i max_size; Size2i size; + Vector2i wb_offset = Vector2i(16, 16); + + NSRect last_frame_rect; bool im_active = false; Size2i im_position; @@ -187,6 +191,8 @@ private: Point2i _get_native_screen_position(int p_screen) const; static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info); + WindowID _get_focused_window_or_popup() const; + static void _dispatch_input_events(const Ref<InputEvent> &p_event); void _dispatch_input_event(const Ref<InputEvent> &p_event); void _push_input(const Ref<InputEvent> &p_event); @@ -387,6 +393,7 @@ public: virtual bool window_maximize_on_title_dbl_click() const override; virtual bool window_minimize_on_title_dbl_click() const override; + virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) override; virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override; virtual Point2i ime_get_selection() const override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 91c6da5d13..2d67bcb44f 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -30,6 +30,7 @@ #include "display_server_macos.h" +#include "godot_button_view.h" #include "godot_content_view.h" #include "godot_menu_delegate.h" #include "godot_menu_item.h" @@ -317,6 +318,15 @@ void DisplayServerMacOS::_displays_arrangement_changed(CGDirectDisplayID display } } +DisplayServer::WindowID DisplayServerMacOS::_get_focused_window_or_popup() const { + const List<WindowID>::Element *E = popup_list.back(); + if (E) { + return E->get(); + } + + return last_focused_window; +} + void DisplayServerMacOS::_dispatch_input_events(const Ref<InputEvent> &p_event) { ((DisplayServerMacOS *)(get_singleton()))->_dispatch_input_event(p_event); } @@ -1828,7 +1838,10 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) { return; } - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } WindowData &wd = windows[window_id]; if (p_mode == MOUSE_MODE_CAPTURED) { // Apple Docs state that the display parameter is not used. @@ -1943,7 +1956,10 @@ void DisplayServerMacOS::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ if (mouse_mode != MOUSE_MODE_CAPTURED) { - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } WindowData &wd = windows[window_id]; // Local point in window coords. @@ -2624,6 +2640,14 @@ bool DisplayServerMacOS::window_minimize_on_title_dbl_click() const { return false; } +void DisplayServerMacOS::window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + wd.wb_offset = p_offset; +} + Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const { _THREAD_SAFE_METHOD_ @@ -2667,14 +2691,31 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win } break; case WINDOW_FLAG_EXTEND_TO_TITLE: { NSRect rect = [wd.window_object frame]; + if (wd.window_button_view) { + [wd.window_button_view removeFromSuperview]; + wd.window_button_view = nil; + } if (p_enabled) { [wd.window_object setTitlebarAppearsTransparent:YES]; [wd.window_object setTitleVisibility:NSWindowTitleHidden]; [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskFullSizeContentView]; + + [[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:YES]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; + [[wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:YES]; + float window_buttons_spacing = NSMinX([[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]) - NSMinX([[wd.window_object standardWindowButton:NSWindowCloseButton] frame]); + + wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect]; + [wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(wd.wb_offset.x, wd.wb_offset.y)]; + [wd.window_view addSubview:wd.window_button_view]; } else { [wd.window_object setTitlebarAppearsTransparent:NO]; [wd.window_object setTitleVisibility:NSWindowTitleVisible]; [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskFullSizeContentView]; + + [[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:NO]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO]; + [[wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:NO]; } [wd.window_object setFrame:rect display:YES]; } break; @@ -3537,7 +3578,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM [apple_menu addItem:[NSMenuItem separatorItem]]; - title = [NSString stringWithFormat:NSLocalizedString(@"\t\tQuit %@", nil), nsappname]; + title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname]; [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; // Add items to the menu bar. diff --git a/platform/macos/godot_button_view.h b/platform/macos/godot_button_view.h new file mode 100644 index 0000000000..e41910878d --- /dev/null +++ b/platform/macos/godot_button_view.h @@ -0,0 +1,51 @@ +/*************************************************************************/ +/* godot_button_view.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_BUTTON_VIEW_H +#define GODOT_BUTTON_VIEW_H + +#include "servers/display_server.h" + +#import <AppKit/AppKit.h> +#import <Foundation/Foundation.h> + +@interface GodotButtonView : NSView { + NSTrackingArea *tracking_area; + NSPoint offset; + CGFloat spacing; + bool mouse_in_group; +} + +- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset; +- (void)displayButtons; + +@end + +#endif // GODOT_BUTTON_VIEW_H diff --git a/platform/macos/godot_button_view.mm b/platform/macos/godot_button_view.mm new file mode 100644 index 0000000000..ae04c02bd5 --- /dev/null +++ b/platform/macos/godot_button_view.mm @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* godot_button_view.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godot_button_view.h" + +@implementation GodotButtonView + +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + + tracking_area = nil; + offset = NSMakePoint(8, 8); + spacing = 20; + mouse_in_group = false; + + return self; +} + +- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset { + spacing = button_spacing; + + NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled]; + [close_button setFrameOrigin:NSMakePoint(0, 0)]; + [self addSubview:close_button]; + + NSButton *miniaturize_button = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSWindowStyleMaskTitled]; + [miniaturize_button setFrameOrigin:NSMakePoint(spacing, 0)]; + [self addSubview:miniaturize_button]; + + NSButton *zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled]; + [zoom_button setFrameOrigin:NSMakePoint(spacing * 2, 0)]; + [self addSubview:zoom_button]; + + offset.y = button_offset.y - zoom_button.frame.size.height / 2; + offset.x = button_offset.x - zoom_button.frame.size.width / 2; + + [self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)]; + [self displayButtons]; +} + +- (void)viewDidMoveToWindow { + if (!self.window) { + return; + } + + [self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + [self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)]; +} + +- (BOOL)_mouseInGroup:(NSButton *)button { + return mouse_in_group; +} + +- (void)updateTrackingAreas { + if (tracking_area != nil) { + [self removeTrackingArea:tracking_area]; + } + + NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect; + tracking_area = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:options owner:self userInfo:nil]; + + [self addTrackingArea:tracking_area]; +} + +- (void)mouseEntered:(NSEvent *)event { + [super mouseEntered:event]; + + mouse_in_group = true; + [self displayButtons]; +} + +- (void)mouseExited:(NSEvent *)event { + [super mouseExited:event]; + + mouse_in_group = false; + [self displayButtons]; +} + +- (void)displayButtons { + for (NSView *subview in self.subviews) { + [subview setNeedsDisplay:YES]; + } +} + +@end diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm index f93ef48f6c..cb70a5db86 100644 --- a/platform/macos/godot_content_view.mm +++ b/platform/macos/godot_content_view.mm @@ -61,6 +61,24 @@ @implementation GodotContentView - (void)setFrameSize:(NSSize)newSize { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (ds && ds->has_window(window_id)) { + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + NSRect frameRect = [wd.window_object frame]; + bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x); + bool top = (wd.last_frame_rect.origin.y == frameRect.origin.y); + if (left && top) { + self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight; + } else if (left && !top) { + self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight; + } else if (!left && top) { + self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft; + } else { + self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft; + } + wd.last_frame_rect = frameRect; + } + [super setFrameSize:newSize]; [self.layer setNeedsDisplay]; // Force "drawRect" call. } diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index 2d9329ab3c..f7f16b1e0e 100644 --- a/platform/macos/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -31,6 +31,7 @@ #include "godot_window_delegate.h" #include "display_server_macos.h" +#include "godot_button_view.h" @implementation GodotWindowDelegate @@ -151,7 +152,9 @@ - (void)windowWillStartLiveResize:(NSNotification *)notification { DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); - if (ds) { + if (ds && ds->has_window(window_id)) { + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + wd.last_frame_rect = [wd.window_object frame]; ds->set_is_resizing(true); } } @@ -217,6 +220,10 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + if (wd.window_button_view) { + [(GodotButtonView *)wd.window_button_view displayButtons]; + } + if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) { const NSRect content_rect = [wd.window_view frame]; NSRect point_in_window_rect = NSMakeRect(content_rect.size.width / 2, content_rect.size.height / 2, 0, 0); @@ -239,6 +246,10 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + if (wd.window_button_view) { + [(GodotButtonView *)wd.window_button_view displayButtons]; + } + ds->release_pressed_events(); ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h index 61db99689c..46e7c17ebe 100644 --- a/platform/macos/os_macos.h +++ b/platform/macos/os_macos.h @@ -75,6 +75,8 @@ public: virtual List<String> get_cmdline_platform_args() const override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index c250a9d71a..ae8534f6ab 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -134,6 +134,15 @@ String OS_MacOS::get_name() const { return "macOS"; } +String OS_MacOS::get_distribution_name() const { + return get_name(); +} + +String OS_MacOS::get_version() const { + NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion; + return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion); +} + void OS_MacOS::alert(const String &p_alert, const String &p_title) { NSAlert *window = [[NSAlert alloc] init]; NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 791328964b..8050d299f0 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -444,6 +444,16 @@ String OS_UWP::get_name() const { return "UWP"; } +String OS_UWP::get_distribution_name() const { + return get_name(); +} + +String OS_UWP::get_version() const { + winrt::hstring df_version = VersionInfo().DeviceFamilyVersion(); + static String version = String(winrt::to_string(df_version).c_str()); + return version; +} + OS::DateTime OS_UWP::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 7d4224cf74..0c1c4a793a 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -183,6 +183,8 @@ public: virtual MainLoop *get_main_loop() const; virtual String get_name() const; + virtual String get_distribution_name() const; + virtual String get_version() const; virtual DateTime get_datetime(bool p_utc) const; virtual TimeZoneInfo get_time_zone_info() const; diff --git a/platform/web/.eslintrc.engine.js b/platform/web/.eslintrc.engine.js index 78df6d41d9..a76bd46b9e 100644 --- a/platform/web/.eslintrc.engine.js +++ b/platform/web/.eslintrc.engine.js @@ -5,6 +5,7 @@ module.exports = { "globals": { "InternalConfig": true, "Godot": true, + "Features": true, "Preloader": true, }, }; diff --git a/platform/web/SCsub b/platform/web/SCsub index e8d0181ede..013b734be2 100644 --- a/platform/web/SCsub +++ b/platform/web/SCsub @@ -66,6 +66,7 @@ sys_env.Depends(build[0], sys_env["JS_PRE"]) sys_env.Depends(build[0], sys_env["JS_EXTERNS"]) engine = [ + "js/engine/features.js", "js/engine/preloader.js", "js/engine/config.js", "js/engine/engine.js", diff --git a/platform/web/detect.py b/platform/web/detect.py index 08f964db92..9cce73efc4 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -109,6 +109,10 @@ def configure(env): env["ENV"] = os.environ # LTO + + if env["lto"] == "auto": # Full LTO for production. + env["lto"] = "full" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index 306453c1eb..1c327fe4b2 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -307,13 +307,7 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset> } if (p_preset->get("vram_texture_compression/for_mobile")) { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "opengl3") { - r_features->push_back("etc"); - } else if (driver == "vulkan") { - // FIXME: Review if this is correct. - r_features->push_back("etc2"); - } + r_features->push_back("etc2"); } r_features->push_back("wasm32"); } diff --git a/platform/web/js/engine/engine.js b/platform/web/js/engine/engine.js index 6f0d51b2be..9227aa1f05 100644 --- a/platform/web/js/engine/engine.js +++ b/platform/web/js/engine/engine.js @@ -61,20 +61,6 @@ const Engine = (function () { }; /** - * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for. - * - * @param {number=} [majorVersion=1] The major WebGL version to check for. - * @returns {boolean} If the given major version of WebGL is available. - * @function Engine.isWebGLAvailable - */ - Engine.isWebGLAvailable = function (majorVersion = 1) { - try { - return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]); - } catch (e) { /* Not available */ } - return false; - }; - - /** * Safe Engine constructor, creates a new prototype for every new instance to avoid prototype pollution. * @ignore * @constructor @@ -265,14 +251,21 @@ const Engine = (function () { // Also expose static methods as instance methods Engine.prototype['load'] = Engine.load; Engine.prototype['unload'] = Engine.unload; - Engine.prototype['isWebGLAvailable'] = Engine.isWebGLAvailable; return new Engine(initConfig); } // Closure compiler exported static methods. SafeEngine['load'] = Engine.load; SafeEngine['unload'] = Engine.unload; - SafeEngine['isWebGLAvailable'] = Engine.isWebGLAvailable; + + // Feature-detection utilities. + SafeEngine['isWebGLAvailable'] = Features.isWebGLAvailable; + SafeEngine['isFetchAvailable'] = Features.isFetchAvailable; + SafeEngine['isSecureContext'] = Features.isSecureContext; + SafeEngine['isCrossOriginIsolated'] = Features.isCrossOriginIsolated; + SafeEngine['isSharedArrayBufferAvailable'] = Features.isSharedArrayBufferAvailable; + SafeEngine['isAudioWorkletAvailable'] = Features.isAudioWorkletAvailable; + SafeEngine['getMissingFeatures'] = Features.getMissingFeatures; return SafeEngine; }()); diff --git a/platform/web/js/engine/features.js b/platform/web/js/engine/features.js new file mode 100644 index 0000000000..f91a4eff81 --- /dev/null +++ b/platform/web/js/engine/features.js @@ -0,0 +1,96 @@ +const Features = { // eslint-disable-line no-unused-vars + /** + * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for. + * + * @param {number=} [majorVersion=1] The major WebGL version to check for. + * @returns {boolean} If the given major version of WebGL is available. + * @function Engine.isWebGLAvailable + */ + isWebGLAvailable: function (majorVersion = 1) { + try { + return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]); + } catch (e) { /* Not available */ } + return false; + }, + + /** + * Check whether the Fetch API available and supports streaming responses. + * + * @returns {boolean} If the Fetch API is available and supports streaming responses. + * @function Engine.isFetchAvailable + */ + isFetchAvailable: function () { + return 'fetch' in window && 'Response' in window && 'body' in window.Response.prototype; + }, + + /** + * Check whether the engine is running in a Secure Context. + * + * @returns {boolean} If the engine is running in a Secure Context. + * @function Engine.isSecureContext + */ + isSecureContext: function () { + return window['isSecureContext'] === true; + }, + + /** + * Check whether the engine is cross origin isolated. + * This value is dependent on Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers sent by the server. + * + * @returns {boolean} If the engine is running in a Secure Context. + * @function Engine.isSecureContext + */ + isCrossOriginIsolated: function () { + return window['crossOriginIsolated'] === true; + }, + + /** + * Check whether SharedBufferArray is available. + * + * Most browsers require the page to be running in a secure context, and the + * the server to provide specific CORS headers for SharedArrayBuffer to be available. + * + * @returns {boolean} If SharedArrayBuffer is available. + * @function Engine.isSharedArrayBufferAvailable + */ + isSharedArrayBufferAvailable: function () { + return 'SharedArrayBuffer' in window; + }, + + /** + * Check whether the AudioContext supports AudioWorkletNodes. + * + * @returns {boolean} If AudioWorkletNode is available. + * @function Engine.isAudioWorkletAvailable + */ + isAudioWorkletAvailable: function () { + return 'AudioContext' in window && 'audioWorklet' in AudioContext.prototype; + }, + + /** + * Return an array of missing required features (as string). + * + * @returns {Array<string>} A list of human-readable missing features. + * @function Engine.getMissingFeatures + */ + getMissingFeatures: function () { + const missing = []; + if (!Features.isWebGLAvailable(2)) { + missing.push('WebGL2'); + } + if (!Features.isFetchAvailable()) { + missing.push('Fetch'); + } + if (!Features.isSecureContext()) { + missing.push('Secure Context'); + } + if (!Features.isCrossOriginIsolated()) { + missing.push('Cross Origin Isolation'); + } + if (!Features.isSharedArrayBufferAvailable()) { + missing.push('SharedArrayBuffer'); + } + // Audio is normally optional since we have a dummy fallback. + return missing; + }, +}; diff --git a/platform/web/package.json b/platform/web/package.json index a57205415a..0a8d9e4334 100644 --- a/platform/web/package.json +++ b/platform/web/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "description": "Development and linting setup for Godot's Web platform code", "scripts": { - "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js --destination ''", + "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js js/engine/features.js --destination ''", "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools", "lint:engine": "eslint \"js/engine/*.js\" --no-eslintrc -c .eslintrc.engine.js", "lint:libs": "eslint \"js/libs/*.js\" --no-eslintrc -c .eslintrc.libs.js", diff --git a/platform/windows/detect.py b/platform/windows/detect.py index e6e1874fc0..52a959b34a 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -448,6 +448,9 @@ def configure_msvc(env, vcvars_msvc_config): ## LTO + if env["lto"] == "auto": # No LTO by default for MSVC, doesn't help. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") @@ -564,6 +567,11 @@ def configure_mingw(env): if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]): env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib" + ## LTO + + if env["lto"] == "auto": # Full LTO for production with MinGW. + env["lto"] = "full" + if env["lto"] != "none": if env["lto"] == "thin": if not env["use_llvm"]: diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 237215c198..4553f31480 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -104,7 +104,10 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { if (windows.has(MAIN_WINDOW_ID) && (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN)) { // Mouse is grabbed (captured or confined). - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } WindowData &wd = windows[window_id]; @@ -119,11 +122,15 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { ClientToScreen(wd.hWnd, &pos); SetCursorPos(pos.x, pos.y); SetCapture(wd.hWnd); + + _register_raw_input_devices(window_id); } } else { // Mouse is free to move around (not captured or confined). ReleaseCapture(); ClipCursor(nullptr); + + _register_raw_input_devices(INVALID_WINDOW_ID); } if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) { @@ -139,6 +146,37 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { } } +DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() const { + const List<WindowID>::Element *E = popup_list.back(); + if (E) { + return E->get(); + } + + return last_focused_window; +} + +void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) { + use_raw_input = true; + + RAWINPUTDEVICE rid[1] = {}; + rid[0].usUsagePage = 0x01; + rid[0].usUsage = 0x02; + rid[0].dwFlags = 0; + + if (p_target_window != INVALID_WINDOW_ID && windows.has(p_target_window)) { + // Follow the defined window + rid[0].hwndTarget = windows[p_target_window].hWnd; + } else { + // Follow the keyboard focus + rid[0].hwndTarget = 0; + } + + if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) { + // Registration failed. + use_raw_input = false; + } +} + bool DisplayServerWindows::tts_is_speaking() const { ERR_FAIL_COND_V(!tts, false); return tts->is_speaking(); @@ -194,7 +232,9 @@ DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const { void DisplayServerWindows::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ - if (!windows.has(last_focused_window)) { + WindowID window_id = _get_focused_window_or_popup(); + + if (!windows.has(window_id)) { return; // No focused window? } @@ -205,7 +245,7 @@ void DisplayServerWindows::warp_mouse(const Point2i &p_position) { POINT p; p.x = p_position.x; p.y = p_position.y; - ClientToScreen(windows[last_focused_window].hWnd, &p); + ClientToScreen(windows[window_id].hWnd, &p); SetCursorPos(p.x, p.y); } @@ -2483,7 +2523,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA old_y = coords.y; } - if (windows[window_id].window_has_focus && mm->get_relative() != Vector2()) { + if ((windows[window_id].window_has_focus || windows[window_id].is_popup) && mm->get_relative() != Vector2()) { Input::get_singleton()->parse_input_event(mm); } } @@ -3773,19 +3813,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win return; } - use_raw_input = true; - - RAWINPUTDEVICE Rid[1]; - - Rid[0].usUsagePage = 0x01; - Rid[0].usUsage = 0x02; - Rid[0].dwFlags = 0; - Rid[0].hwndTarget = 0; - - if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) { - // Registration failed. - use_raw_input = false; - } + _register_raw_input_devices(INVALID_WINDOW_ID); #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index fd64a02020..d85d6364bd 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -466,6 +466,8 @@ class DisplayServerWindows : public DisplayServer { void _update_real_mouse_position(WindowID p_window); void _set_mouse_mode_impl(MouseMode p_mode); + WindowID _get_focused_window_or_popup() const; + void _register_raw_input_devices(WindowID p_target_window); void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam); void _process_key_events(); diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index cdd1c14978..36b0919185 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -32,6 +32,38 @@ </Expand> </Type> + <Type Name="HashMap<*,*>"> + <Expand> + <Item Name="[size]">num_elements</Item> + <LinkedListItems> + <Size>num_elements</Size> + <HeadPointer>head_element</HeadPointer> + <NextPointer>next</NextPointer> + <ValueNode>data</ValueNode> + </LinkedListItems> + </Expand> + </Type> + + <Type Name="VMap<*,*>"> + <Expand> + <Item Condition="_cowdata._ptr" Name="[size]">*(reinterpret_cast<int*>(_cowdata._ptr) - 1)</Item> + <ArrayItems Condition="_cowdata._ptr"> + <Size>*(reinterpret_cast<int*>(_cowdata._ptr) - 1)</Size> + <ValuePointer>reinterpret_cast<VMap<$T1,$T2>::Pair*>(_cowdata._ptr)</ValuePointer> + </ArrayItems> + </Expand> + </Type> + + <Type Name="VMap<Callable,*>::Pair"> + <DisplayString Condition="dynamic_cast<CallableCustomMethodPointerBase*>(key.custom)">{dynamic_cast<CallableCustomMethodPointerBase*>(key.custom)->text}</DisplayString> + </Type> + + <!-- requires PR 64364 + <Type Name="GDScriptThreadContext"> + <DisplayString Condition="_is_main == true">main thread {_debug_thread_id}</DisplayString> + </Type> + --> + <Type Name="Variant"> <DisplayString Condition="type == Variant::NIL">nil</DisplayString> <DisplayString Condition="type == Variant::BOOL">{_data._bool}</DisplayString> @@ -55,15 +87,17 @@ <DisplayString Condition="type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{*(PackedByteArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{*(PackedInt32Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<unsigned char>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<int>*>(_data.packed_array)->array}</DisplayString> + <!-- broken, will show incorrect data <DisplayString Condition="type == Variant::PACKED_INT64_ARRAY">{*(PackedInt64Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{*(PackedFloat32Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{*(PackedFloat64Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{*(PackedStringArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{*(PackedVector2Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{*(PackedVector3Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{*(PackedColorArray *)_data._mem}</DisplayString> + --> + <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<float>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<double>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<String>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<Vector2>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<Vector3>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<Color>*>(_data.packed_array)->array}</DisplayString> <StringView Condition="type == Variant::STRING && ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,s32</StringView> @@ -87,7 +121,7 @@ <Item Name="[value]" Condition="type == Variant::OBJECT">*(Object *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::ARRAY">*(Array *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">*(PackedByteArray *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">reinterpret_cast<const Variant::PackedArrayRef<unsigned char>*>(_data.packed_array)->array</Item> <Item Name="[value]" Condition="type == Variant::PACKED_INT32_ARRAY">*(PackedInt32Array *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::PACKED_INT64_ARRAY">*(PackedInt64Array *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::PACKED_FLOAT32_ARRAY">*(PackedFloat32Array *)_data._mem</Item> @@ -105,6 +139,14 @@ <StringView Condition="_cowdata._ptr != 0">_cowdata._ptr,s32</StringView> </Type> + <Type Name="godot::String"> + <DisplayString>{*reinterpret_cast<void**>(opaque),s32}</DisplayString> + <Expand> + <Item Name="opaque_ptr">*reinterpret_cast<void**>(opaque)</Item> + <Item Name="string">*reinterpret_cast<void**>(opaque),s32</Item> + </Expand> + </Type> + <Type Name="StringName"> <DisplayString Condition="_data && _data->cname">{_data->cname}</DisplayString> <DisplayString Condition="_data && !_data->cname">{_data->name,s32}</DisplayString> @@ -113,6 +155,22 @@ <StringView Condition="_data && !_data->cname">_data->name,s32</StringView> </Type> + <!-- can't cast the opaque to ::StringName because Natvis does not support global namespace specifier? --> + <Type Name="godot::StringName"> + <DisplayString Condition="(*reinterpret_cast<const char***>(opaque))[1]">{(*reinterpret_cast<const char***>(opaque))[1],s8}</DisplayString> + <DisplayString Condition="!(*reinterpret_cast<const char***>(opaque))[1]">{(*reinterpret_cast<const char***>(opaque))[2],s32}</DisplayString> + <Expand> + <Item Name="opaque_ptr">*reinterpret_cast<void**>(opaque)</Item> + <Item Name="&cname">(*reinterpret_cast<const char***>(opaque))+1</Item> + <Item Name="cname">(*reinterpret_cast<const char***>(opaque))[1],s8</Item> + </Expand> + </Type> + + <Type Name="Object::SignalData"> + <DisplayString Condition="user.name._cowdata._ptr">"{user.name}" {slot_map}</DisplayString> + <DisplayString Condition="!user.name._cowdata._ptr">"{slot_map}</DisplayString> + </Type> + <Type Name="Vector2"> <DisplayString>{{{x},{y}}}</DisplayString> <Expand> @@ -149,12 +207,4 @@ <Item Name="alpha">a</Item> </Expand> </Type> - - <Type Name="Node" Inheritable="false"> - <Expand> - <Item Name="Object">(Object*)this</Item> - <Item Name="class_name">(StringName*)(((char*)this) + sizeof(Object))</Item> - <Item Name="data">(Node::Data*)(((char*)this) + sizeof(Object) + sizeof(StringName))</Item> - </Expand> - </Type> </AutoVisualizer> diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 2c268ff3d5..1978ec5ab6 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -290,6 +290,24 @@ String OS_Windows::get_name() const { return "Windows"; } +String OS_Windows::get_distribution_name() const { + return get_name(); +} + +String OS_Windows::get_version() const { + typedef LONG NTSTATUS, *PNTSTATUS; + typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); + if (version_ptr != nullptr) { + RTL_OSVERSIONINFOW fow = { 0 }; + fow.dwOSVersionInfoSize = sizeof(fow); + if (version_ptr(&fow) == 0x00000000) { + return vformat("%d.%d.%d", (int64_t)fow.dwMajorVersion, (int64_t)fow.dwMinorVersion, (int64_t)fow.dwBuildNumber); + } + } + return ""; +} + OS::DateTime OS_Windows::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 53451b780e..491de2266f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -143,6 +143,8 @@ public: virtual MainLoop *get_main_loop() const override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual void initialize_joypads() override {} diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 7fe464d2f4..7ee9861d3f 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -63,9 +63,13 @@ Rect2 AnimatedSprite2D::_edit_get_rect() const { } bool AnimatedSprite2D::_edit_use_rect() const { - if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { + if (frames.is_null() || !frames->has_animation(animation)) { return false; } + if (frame < 0 || frame >= frames->get_frame_count(animation)) { + return false; + } + Ref<Texture2D> t; if (animation) { t = frames->get_frame(animation, frame); @@ -79,7 +83,10 @@ Rect2 AnimatedSprite2D::get_anchorable_rect() const { } Rect2 AnimatedSprite2D::_get_rect() const { - if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { + if (frames.is_null() || !frames->has_animation(animation)) { + return Rect2(); + } + if (frame < 0 || frame >= frames->get_frame_count(animation)) { return Rect2(); } @@ -161,29 +168,22 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const { void AnimatedSprite2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_INTERNAL_PROCESS: { - if (frames.is_null()) { + if (frames.is_null() || !frames->has_animation(animation)) { return; } - if (!frames->has_animation(animation)) { - return; - } - if (frame < 0) { - return; + + double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale); + if (speed == 0) { + return; // Do nothing. } + int last_frame = frames->get_frame_count(animation) - 1; double remaining = get_process_delta_time(); - while (remaining) { - double speed = frames->get_animation_speed(animation) * speed_scale; - if (speed == 0) { - return; // Do nothing. - } - if (timeout <= 0) { timeout = _get_frame_duration(); - int last_frame = frames->get_frame_count(animation) - 1; - if (!backwards) { + if (!playing_backwards) { // Forward. if (frame >= last_frame) { if (frames->get_animation_loop(animation)) { @@ -229,13 +229,7 @@ void AnimatedSprite2D::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - if (frames.is_null()) { - return; - } - if (frame < 0) { - return; - } - if (!frames->has_animation(animation)) { + if (frames.is_null() || !frames->has_animation(animation)) { return; } @@ -327,9 +321,14 @@ int AnimatedSprite2D::get_frame() const { } void AnimatedSprite2D::set_speed_scale(double p_speed_scale) { + if (speed_scale == p_speed_scale) { + return; + } + double elapsed = _get_frame_duration() - timeout; - speed_scale = MAX(p_speed_scale, 0.0f); + speed_scale = p_speed_scale; + playing_backwards = signbit(speed_scale) != backwards; // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed. _reset_timeout(); @@ -398,12 +397,13 @@ bool AnimatedSprite2D::is_playing() const { return playing; } -void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) { +void AnimatedSprite2D::play(const StringName &p_animation, bool p_backwards) { backwards = p_backwards; + playing_backwards = signbit(speed_scale) != backwards; if (p_animation) { set_animation(p_animation); - if (frames.is_valid() && backwards && get_frame() == 0) { + if (frames.is_valid() && playing_backwards && get_frame() == 0) { set_frame(frames->get_frame_count(p_animation) - 1); } } @@ -418,7 +418,7 @@ void AnimatedSprite2D::stop() { double AnimatedSprite2D::_get_frame_duration() { if (frames.is_valid() && frames->has_animation(animation)) { - double speed = frames->get_animation_speed(animation) * speed_scale; + double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale); if (speed > 0) { return 1.0 / speed; } @@ -454,11 +454,11 @@ StringName AnimatedSprite2D::get_animation() const { return animation; } -TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray AnimatedSprite2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (frames.is_null()) { - warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.")); + warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite2D to display frames.")); } return warnings; diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index 0a19e250d8..11c4adb816 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -39,6 +39,7 @@ class AnimatedSprite2D : public Node2D { Ref<SpriteFrames> frames; bool playing = false; + bool playing_backwards = false; bool backwards = false; StringName animation = "default"; int frame = 0; @@ -81,7 +82,7 @@ public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); Ref<SpriteFrames> get_sprite_frames() const; - void play(const StringName &p_animation = StringName(), const bool p_backwards = false); + void play(const StringName &p_animation = StringName(), bool p_backwards = false); void stop(); void set_playing(bool p_playing); @@ -108,7 +109,7 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; AnimatedSprite2D(); diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 61a17a4845..330afe4a1b 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -78,8 +78,8 @@ Color CanvasModulate::get_color() const { return color; } -TypedArray<String> CanvasModulate::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray CanvasModulate::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { List<Node *> nodes; diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h index 1fd54898f8..4f522ca1c7 100644 --- a/scene/2d/canvas_modulate.h +++ b/scene/2d/canvas_modulate.h @@ -46,7 +46,7 @@ public: void set_color(const Color &p_color); Color get_color() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; CanvasModulate(); ~CanvasModulate(); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index a79c81e8bd..23948c2fd3 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -565,8 +565,8 @@ void CollisionObject2D::_update_pickable() { } } -TypedArray<String> CollisionObject2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray CollisionObject2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (shapes.is_empty()) { warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape.")); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 48ea59e040..6b778d1b60 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -157,7 +157,7 @@ public: void set_pickable(bool p_enabled); bool is_pickable() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; _FORCE_INLINE_ RID get_rid() const { return rid; } diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index b69b19d30d..d06461b566 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -235,8 +235,8 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl } #endif -TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray CollisionPolygon2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { warnings.push_back(RTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape.")); diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index e18022ab7e..066f7271c6 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -77,7 +77,7 @@ public: void set_polygon(const Vector<Point2> &p_polygon); Vector<Point2> get_polygon() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_disabled(bool p_disabled); bool is_disabled() const; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 039bfee451..7e167a3807 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -168,8 +168,8 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double return shape->_edit_is_selected_on_click(p_point, p_tolerance); } -TypedArray<String> CollisionShape2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray CollisionShape2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { warnings.push_back(RTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape.")); diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index dbc81e8424..5e50420e00 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -72,7 +72,7 @@ public: void set_one_way_collision_margin(real_t p_margin); real_t get_one_way_collision_margin() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; CollisionShape2D(); }; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 4523e5dfe9..eece90190b 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -242,8 +242,8 @@ bool CPUParticles2D::get_fractional_delta() const { return fractional_delta; } -TypedArray<String> CPUParticles2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node2D::get_configuration_warnings(); +PackedStringArray CPUParticles2D::get_configuration_warnings() const { + PackedStringArray warnings = Node2D::get_configuration_warnings(); CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 3fd1c7fd0f..ea735411a8 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -282,7 +282,7 @@ public: void set_gravity(const Vector2 &p_gravity); Vector2 get_gravity() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void restart(); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index bed68b4ee0..18f709f241 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -296,8 +296,8 @@ bool GPUParticles2D::get_interpolate() const { return interpolate; } -TypedArray<String> GPUParticles2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node2D::get_configuration_warnings(); +PackedStringArray GPUParticles2D::get_configuration_warnings() const { + PackedStringArray warnings = Node2D::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose.")); diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 10ae91775f..d613b4ef51 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -145,7 +145,7 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_sub_emitter(const NodePath &p_path); NodePath get_sub_emitter() const; diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index 89b6f3f9da..6000508f36 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -202,8 +202,8 @@ bool Joint2D::get_exclude_nodes_from_collision() const { return exclude_from_collision; } -TypedArray<String> Joint2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node2D::get_configuration_warnings(); +PackedStringArray Joint2D::get_configuration_warnings() const { + PackedStringArray warnings = Node2D::get_configuration_warnings(); if (!warning.is_empty()) { warnings.push_back(warning); diff --git a/scene/2d/joint_2d.h b/scene/2d/joint_2d.h index e3cd600cbd..8b145be6ae 100644 --- a/scene/2d/joint_2d.h +++ b/scene/2d/joint_2d.h @@ -62,7 +62,7 @@ protected: _FORCE_INLINE_ bool is_configured() const { return configured; } public: - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; void set_node_a(const NodePath &p_node_a); NodePath get_node_a() const; diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 7eb6b43af7..90402260ed 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -395,8 +395,8 @@ Vector2 PointLight2D::get_texture_offset() const { return texture_offset; } -TypedArray<String> PointLight2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray PointLight2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!texture.is_valid()) { warnings.push_back(RTR("A texture with the shape of the light must be supplied to the \"Texture\" property.")); diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 373cfe59fd..29870923aa 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -171,7 +171,7 @@ public: void set_texture_scale(real_t p_scale); real_t get_texture_scale() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; PointLight2D(); }; diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 6c171383ca..67e82140e4 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -246,8 +246,8 @@ int LightOccluder2D::get_occluder_light_mask() const { return mask; } -TypedArray<String> LightOccluder2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray LightOccluder2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!occluder_polygon.is_valid()) { warnings.push_back(RTR("An occluder polygon must be set (or drawn) for this occluder to take effect.")); diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index b61e23464a..ee4d87e54b 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -105,7 +105,7 @@ public: void set_as_sdf_collision(bool p_enable); bool is_set_as_sdf_collision() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; LightOccluder2D(); ~LightOccluder2D(); diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index d7f75c63a4..55cebdaadc 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -368,8 +368,8 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) { emit_signal(SNAME("velocity_computed"), velocity); } -TypedArray<String> NavigationAgent2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationAgent2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node2D>(get_parent())) { warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D inheriting parent node.")); diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 11b845665d..2fbacc4c76 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -155,7 +155,7 @@ public: void set_velocity(Vector2 p_velocity); void _avoidance_done(Vector3 p_new_velocity); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; private: void update_navigation(); diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp index 8ba51482ee..3f7e10eaea 100644 --- a/scene/2d/navigation_link_2d.cpp +++ b/scene/2d/navigation_link_2d.cpp @@ -267,8 +267,8 @@ void NavigationLink2D::set_travel_cost(real_t p_travel_cost) { NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost); } -TypedArray<String> NavigationLink2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationLink2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (start_location.is_equal_approx(end_location)) { warnings.push_back(RTR("NavigationLink2D start location should be different than the end location to be useful.")); diff --git a/scene/2d/navigation_link_2d.h b/scene/2d/navigation_link_2d.h index 5990ea082c..2a5092216d 100644 --- a/scene/2d/navigation_link_2d.h +++ b/scene/2d/navigation_link_2d.h @@ -79,7 +79,7 @@ public: void set_travel_cost(real_t p_travel_cost); real_t get_travel_cost() const { return travel_cost; } - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; NavigationLink2D(); ~NavigationLink2D(); diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 1850e00ecd..e46bb79551 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -120,8 +120,8 @@ NavigationObstacle2D::~NavigationObstacle2D() { agent = RID(); // Pointless } -TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationObstacle2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node2D>(get_parent())) { warnings.push_back(RTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.")); diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index 6eff95adec..d4c1df343f 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -73,7 +73,7 @@ public: return radius; } - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; private: void initialize_agent(); diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index ffccb95a22..b1e2875a8b 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -566,8 +566,8 @@ void NavigationRegion2D::_map_changed(RID p_map) { #endif // DEBUG_ENABLED } -TypedArray<String> NavigationRegion2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node2D::get_configuration_warnings(); +PackedStringArray NavigationRegion2D::get_configuration_warnings() const { + PackedStringArray warnings = Node2D::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { if (!navpoly.is_valid()) { diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 3c9df91fe3..893de41a94 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -134,7 +134,7 @@ public: void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); Ref<NavigationPolygon> get_navigation_polygon() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; NavigationRegion2D(); ~NavigationRegion2D(); diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index bd5a01f5a4..f1a28b7852 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -102,9 +102,9 @@ void ParallaxBackground::_update_scroll() { } if (ignore_camera_zoom) { - l->set_base_offset_and_scale((ofs + screen_offset * (scale - 1)) / scale, 1.0, screen_offset); + l->set_base_offset_and_scale((ofs + screen_offset * (scale - 1)) / scale, 1.0); } else { - l->set_base_offset_and_scale(ofs, scale, screen_offset); + l->set_base_offset_and_scale(ofs, scale); } } } diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index f0aad1b8a4..01e4bf19f3 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -39,7 +39,7 @@ void ParallaxLayer::set_motion_scale(const Size2 &p_scale) { if (pb && is_inside_tree()) { Vector2 ofs = pb->get_final_offset(); real_t scale = pb->get_scroll_scale(); - set_base_offset_and_scale(ofs, scale, screen_offset); + set_base_offset_and_scale(ofs, scale); } } @@ -54,7 +54,7 @@ void ParallaxLayer::set_motion_offset(const Size2 &p_offset) { if (pb && is_inside_tree()) { Vector2 ofs = pb->get_final_offset(); real_t scale = pb->get_scroll_scale(); - set_base_offset_and_scale(ofs, scale, screen_offset); + set_base_offset_and_scale(ofs, scale); } } @@ -111,9 +111,7 @@ void ParallaxLayer::_notification(int p_what) { } } -void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset) { - screen_offset = p_screen_offset; - +void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale) { if (!is_inside_tree()) { return; } @@ -121,7 +119,7 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s return; } - Point2 new_ofs = (screen_offset + (p_offset - screen_offset) * motion_scale) + motion_offset * p_scale + orig_offset * p_scale; + Point2 new_ofs = p_offset * motion_scale + motion_offset * p_scale + orig_offset * p_scale; if (mirroring.x) { real_t den = mirroring.x * p_scale; @@ -139,8 +137,8 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s _update_mirroring(); } -TypedArray<String> ParallaxLayer::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray ParallaxLayer::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<ParallaxBackground>(get_parent())) { warnings.push_back(RTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.")); diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h index b4dcf0ea61..6471f56c5c 100644 --- a/scene/2d/parallax_layer.h +++ b/scene/2d/parallax_layer.h @@ -43,8 +43,6 @@ class ParallaxLayer : public Node2D { Vector2 mirroring; void _update_mirroring(); - Point2 screen_offset; - protected: void _notification(int p_what); static void _bind_methods(); @@ -59,9 +57,9 @@ public: void set_mirroring(const Size2 &p_mirroring); Size2 get_mirroring() const; - void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset); + void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; ParallaxLayer(); }; diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 90b2e3d460..c1044fdf5b 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -256,8 +256,8 @@ void PathFollow2D::_validate_property(PropertyInfo &p_property) const { } } -TypedArray<String> PathFollow2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray PathFollow2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { if (!Object::cast_to<Path2D>(get_parent())) { diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 3d66ca1fab..5e436fb9f6 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -106,7 +106,7 @@ public: void set_cubic_interpolation(bool p_enable); bool get_cubic_interpolation() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; PathFollow2D() {} }; diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp index e6933b8a40..5ff706ebb7 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physical_bone_2d.cpp @@ -106,8 +106,8 @@ void PhysicalBone2D::_find_joint_child() { } } -TypedArray<String> PhysicalBone2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray PhysicalBone2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!parent_skeleton) { warnings.push_back(RTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!")); diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h index 9fbfa04100..33ac0d9935 100644 --- a/scene/2d/physical_bone_2d.h +++ b/scene/2d/physical_bone_2d.h @@ -79,7 +79,7 @@ public: void set_follow_bone_when_simulating(bool p_follow); bool get_follow_bone_when_simulating() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; PhysicalBone2D(); ~PhysicalBone2D(); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index f081984956..16686f4fe6 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); - ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); @@ -54,9 +54,9 @@ PhysicsBody2D::~PhysicsBody2D() { } } -Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin) { +Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin); - parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery. + parameters.recovery_as_collision = p_recovery_as_collision; PhysicsServer2D::MotionResult result; @@ -128,7 +128,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_ return colliding; } -bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer2D::MotionResult *r = nullptr; @@ -141,7 +141,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distan } PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin); - parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery. + parameters.recovery_as_collision = p_recovery_as_collision; return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); } @@ -911,10 +911,10 @@ void RigidBody2D::_notification(int p_what) { #endif } -TypedArray<String> RigidBody2D::get_configuration_warnings() const { +PackedStringArray RigidBody2D::get_configuration_warnings() const { Transform2D t = get_transform(); - TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings(); + PackedStringArray warnings = CollisionObject2D::get_configuration_warnings(); if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) { warnings.push_back(RTR("Size changes to RigidBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); @@ -1134,7 +1134,6 @@ bool CharacterBody2D::move_and_slide() { if (!current_platform_velocity.is_zero_approx()) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. parameters.exclude_bodies.insert(platform_rid); if (platform_object_id.is_valid()) { parameters.exclude_objects.insert(platform_object_id); @@ -1193,7 +1192,6 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. Vector2 prev_position = parameters.from.columns[2]; @@ -1350,7 +1348,6 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { bool first_slide = true; for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. PhysicsServer2D::MotionResult result; bool collided = move_and_collide(parameters, result, false, false); @@ -1397,7 +1394,7 @@ void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_ real_t length = MAX(floor_snap_length, margin); PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection. parameters.collide_separation_ray = true; PhysicsServer2D::MotionResult result; @@ -1433,7 +1430,7 @@ bool CharacterBody2D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_f real_t length = MAX(floor_snap_length, margin); PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection. parameters.collide_separation_ray = true; PhysicsServer2D::MotionResult result; diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index eaba9aadad..932ec1de16 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -47,11 +47,11 @@ protected: Ref<KinematicCollision2D> motion_cache; - Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08); + Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false); public: bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); + bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false); TypedArray<PhysicsBody2D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody @@ -309,7 +309,7 @@ public: TypedArray<Node2D> get_colliding_bodies() const; //function for script - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; RigidBody2D(); ~RigidBody2D(); diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index 6c4bfd58ce..f4343e4c03 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -183,8 +183,8 @@ void RemoteTransform2D::force_update_cache() { _update_cache(); } -TypedArray<String> RemoteTransform2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray RemoteTransform2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) { warnings.push_back(RTR("Path property must point to a valid Node2D node to work.")); diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h index bd352e1054..f98eec75c6 100644 --- a/scene/2d/remote_transform_2d.h +++ b/scene/2d/remote_transform_2d.h @@ -70,7 +70,7 @@ public: void force_update_cache(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; RemoteTransform2D(); }; diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index a25d5934ee..6222b0db14 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -391,8 +391,8 @@ Array ShapeCast2D::_get_collision_result() const { return ret; } -TypedArray<String> ShapeCast2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node2D::get_configuration_warnings(); +PackedStringArray ShapeCast2D::get_configuration_warnings() const { + PackedStringArray warnings = Node2D::get_configuration_warnings(); if (shape.is_null()) { warnings.push_back(RTR("This node cannot interact with other objects unless a Shape2D is assigned.")); diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h index 660e52f189..7b55566b01 100644 --- a/scene/2d/shape_cast_2d.h +++ b/scene/2d/shape_cast_2d.h @@ -117,7 +117,7 @@ public: void remove_exception(const CollisionObject2D *p_node); void clear_exceptions(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; }; #endif // SHAPE_CAST_2D_H diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 8f0bf22617..b5759c54f7 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -434,8 +434,8 @@ int Bone2D::get_index_in_skeleton() const { return skeleton_index; } -TypedArray<String> Bone2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray Bone2D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!skeleton) { if (parent_bone) { warnings.push_back(RTR("This Bone2D chain should end at a Skeleton2D node.")); diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 98fb867d99..580aed97ce 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -78,7 +78,7 @@ public: void apply_rest(); Transform2D get_skeleton_rest() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_default_length(real_t p_length); real_t get_default_length() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 5de6d547d7..42b76d0136 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -3819,8 +3819,8 @@ void TileMap::draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Co #undef DRAW_SIDE_IF_NEEDED } -TypedArray<String> TileMap::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray TileMap::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); // Retrieve the set of Z index values with a Y-sorted layer. RBSet<int> y_sorted_z_index; diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index a819eeab71..b1a2118c6b 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -406,7 +406,7 @@ public: GDVIRTUAL3(_tile_data_runtime_update, int, Vector2i, TileData *); // Configuration warnings. - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; TileMap(); ~TileMap(); diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index b3ff6497a7..7b0a6c7e3e 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -100,8 +100,8 @@ void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const { } } -TypedArray<String> BoneAttachment3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node3D::get_configuration_warnings(); +PackedStringArray BoneAttachment3D::get_configuration_warnings() const { + PackedStringArray warnings = Node3D::get_configuration_warnings(); if (use_external_skeleton) { if (external_skeleton_node_cache.is_null()) { diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index f85053e614..2db6ba6268 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -76,7 +76,7 @@ protected: #endif // TOOLS_ENABLED public: - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; void set_bone_name(const String &p_name); String get_bone_name() const; diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index f5e3e8b015..c3c1c8ba36 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -703,8 +703,8 @@ bool CollisionObject3D::get_capture_input_on_drag() const { return capture_input_on_drag; } -TypedArray<String> CollisionObject3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray CollisionObject3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (shapes.is_empty()) { 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.")); diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index c638be9d90..1406e6c698 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -164,7 +164,7 @@ public: _FORCE_INLINE_ RID get_rid() const { return rid; } - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; CollisionObject3D(); ~CollisionObject3D(); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index 90099d787b..81b2c85de4 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -167,8 +167,8 @@ void CollisionPolygon3D::set_margin(real_t p_margin) { } } -TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +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.")); diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h index 74e5867a2f..bbcea539b2 100644 --- a/scene/3d/collision_polygon_3d.h +++ b/scene/3d/collision_polygon_3d.h @@ -74,7 +74,7 @@ public: real_t get_margin() const; void set_margin(real_t p_margin); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; CollisionPolygon3D(); }; diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index a9bc28b464..7a0001bc6f 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -114,8 +114,8 @@ void CollisionShape3D::resource_changed(Ref<Resource> res) { update_gizmos(); } -TypedArray<String> CollisionShape3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray CollisionShape3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { warnings.push_back(RTR("CollisionShape3D 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.")); diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h index 124c0d166d..70653daa19 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/collision_shape_3d.h @@ -62,7 +62,7 @@ public: void set_disabled(bool p_disabled); bool is_disabled() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; CollisionShape3D(); ~CollisionShape3D(); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index d7bf76a6f6..ef373cf9ca 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -188,8 +188,8 @@ bool CPUParticles3D::get_fractional_delta() const { return fractional_delta; } -TypedArray<String> CPUParticles3D::get_configuration_warnings() const { - TypedArray<String> warnings = GeometryInstance3D::get_configuration_warnings(); +PackedStringArray CPUParticles3D::get_configuration_warnings() const { + PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings(); bool mesh_found = false; bool anim_material_found = false; diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index d84b0aedd2..26c702172b 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -302,7 +302,7 @@ public: void set_gravity(const Vector3 &p_gravity); Vector3 get_gravity() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void restart(); diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index 460402ad1d..fc442986a8 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -158,8 +158,8 @@ void Decal::_validate_property(PropertyInfo &p_property) const { } } -TypedArray<String> Decal::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray Decal::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (textures[TEXTURE_ALBEDO].is_null() && textures[TEXTURE_NORMAL].is_null() && textures[TEXTURE_ORM].is_null() && textures[TEXTURE_EMISSION].is_null()) { warnings.push_back(RTR("The decal has no textures loaded into any of its texture properties, and will therefore not be visible.")); diff --git a/scene/3d/decal.h b/scene/3d/decal.h index 1a7d55b108..ab39350b75 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -65,7 +65,7 @@ protected: void _validate_property(PropertyInfo &p_property) const; public: - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index cfee7028d4..4606e70310 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -99,8 +99,8 @@ AABB FogVolume::get_aabb() const { return AABB(); } -TypedArray<String> FogVolume::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray FogVolume::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); Ref<Environment> environment = get_viewport()->find_world_3d()->get_environment(); diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h index fcdc1e2807..d79836be0e 100644 --- a/scene/3d/fog_volume.h +++ b/scene/3d/fog_volume.h @@ -62,7 +62,7 @@ public: Ref<Material> get_material() const; virtual AABB get_aabb() const override; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; FogVolume(); ~FogVolume(); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index bd63939d74..dbbf196f7a 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -269,8 +269,8 @@ bool GPUParticles3D::get_interpolate() const { return interpolate; } -TypedArray<String> GPUParticles3D::get_configuration_warnings() const { - TypedArray<String> warnings = GeometryInstance3D::get_configuration_warnings(); +PackedStringArray GPUParticles3D::get_configuration_warnings() const { + PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose.")); diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 2ad9672474..ef92218e4d 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -147,7 +147,7 @@ public: void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh); Ref<Mesh> get_draw_pass_mesh(int p_pass) const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_sub_emitter(const NodePath &p_path); NodePath get_sub_emitter() const; diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 24bfa7b6de..d3f53d9c0d 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -503,8 +503,8 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() { return ret; } -TypedArray<String> GPUParticlesCollisionSDF3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray GPUParticlesCollisionSDF3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (bake_mask == 0) { warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property.")); diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h index 712bd015ff..548552bb70 100644 --- a/scene/3d/gpu_particles_collision_3d.h +++ b/scene/3d/gpu_particles_collision_3d.h @@ -162,7 +162,7 @@ protected: static void _bind_methods(); public: - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; void set_thickness(float p_thickness); float get_thickness() const; diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index 7dc094062b..1a18f43e7b 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -198,8 +198,8 @@ bool Joint3D::get_exclude_nodes_from_collision() const { return exclude_from_collision; } -TypedArray<String> Joint3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node3D::get_configuration_warnings(); +PackedStringArray Joint3D::get_configuration_warnings() const { + PackedStringArray warnings = Node3D::get_configuration_warnings(); if (!warning.is_empty()) { warnings.push_back(warning); diff --git a/scene/3d/joint_3d.h b/scene/3d/joint_3d.h index cb967023e8..5af427446f 100644 --- a/scene/3d/joint_3d.h +++ b/scene/3d/joint_3d.h @@ -63,7 +63,7 @@ protected: _FORCE_INLINE_ bool is_configured() const { return configured; } public: - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; void set_node_a(const NodePath &p_node_a); NodePath get_node_a() const; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index e51f06e083..23fd091be6 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -578,8 +578,8 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const { return shadow_mode; } -TypedArray<String> OmniLight3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray OmniLight3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!has_shadow() && get_projector().is_valid()) { warnings.push_back(RTR("Projector texture only works with shadows active.")); @@ -608,8 +608,8 @@ OmniLight3D::OmniLight3D() : set_param(PARAM_SHADOW_BIAS, 0.2); } -TypedArray<String> SpotLight3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray SpotLight3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) { warnings.push_back(RTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.")); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index e43d6f0419..8da45bee79 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -216,7 +216,7 @@ public: void set_shadow_mode(ShadowMode p_mode); ShadowMode get_shadow_mode() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; OmniLight3D(); }; @@ -230,7 +230,7 @@ protected: static void _bind_methods(); public: - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; SpotLight3D() : Light3D(RenderingServer::LIGHT_SPOT) {} diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index b0bccc4571..555884f445 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -1418,7 +1418,8 @@ float LightmapGI::get_bias() const { } void LightmapGI::set_max_texture_size(int p_size) { - ERR_FAIL_COND(p_size < 2048); + ERR_FAIL_COND_MSG(p_size < 2048, vformat("The LightmapGI maximum texture size supplied (%d) is too small. The minimum allowed value is 2048.", p_size)); + ERR_FAIL_COND_MSG(p_size > 16384, vformat("The LightmapGI maximum texture size supplied (%d) is too large. The maximum allowed value is 16384.", p_size)); max_texture_size = p_size; } @@ -1506,7 +1507,7 @@ void LightmapGI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size"), "set_max_texture_size", "get_max_texture_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size", PROPERTY_HINT_RANGE, "2048,16384,1"), "set_max_texture_size", "get_max_texture_size"); ADD_GROUP("Environment", "environment_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_mode", PROPERTY_HINT_ENUM, "Disabled,Scene,Custom Sky,Custom Color"), "set_environment_mode", "get_environment_mode"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky"); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 0062a4a093..1d282e92c8 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -142,16 +142,16 @@ public: private: BakeQuality bake_quality = BAKE_QUALITY_MEDIUM; bool use_denoiser = true; - int bounces = 1; + int bounces = 3; float bias = 0.0005; int max_texture_size = 16384; bool interior = false; - EnvironmentMode environment_mode = ENVIRONMENT_MODE_DISABLED; + EnvironmentMode environment_mode = ENVIRONMENT_MODE_SCENE; Ref<Sky> environment_custom_sky; - Color environment_custom_color = Color(0.2, 0.7, 1.0); + Color environment_custom_color = Color(1, 1, 1); float environment_custom_energy = 1.0; bool directional = false; - GenerateProbes gen_probes = GENERATE_PROBES_DISABLED; + GenerateProbes gen_probes = GENERATE_PROBES_SUBDIV_8; Ref<CameraAttributes> camera_attributes; Ref<LightmapGIData> light_data; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 34e84861a2..3476ced6ee 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -383,8 +383,8 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) { emit_signal(SNAME("velocity_computed"), p_new_velocity); } -TypedArray<String> NavigationAgent3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationAgent3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node3D>(get_parent())) { warnings.push_back(RTR("The NavigationAgent3D can be used only under a Node3D inheriting parent node.")); diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 35c1b1175a..eed6457f4a 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -167,7 +167,7 @@ public: void set_velocity(Vector3 p_velocity); void _avoidance_done(Vector3 p_new_velocity); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; private: void update_navigation(); diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp index 47b602c966..78fe4754ea 100644 --- a/scene/3d/navigation_link_3d.cpp +++ b/scene/3d/navigation_link_3d.cpp @@ -378,8 +378,8 @@ void NavigationLink3D::set_travel_cost(real_t p_travel_cost) { NavigationServer3D::get_singleton()->link_set_travel_cost(link, travel_cost); } -TypedArray<String> NavigationLink3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationLink3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (start_location.is_equal_approx(end_location)) { warnings.push_back(RTR("NavigationLink3D start location should be different than the end location to be useful.")); diff --git a/scene/3d/navigation_link_3d.h b/scene/3d/navigation_link_3d.h index 1f88075527..1fc03546fa 100644 --- a/scene/3d/navigation_link_3d.h +++ b/scene/3d/navigation_link_3d.h @@ -84,7 +84,7 @@ public: void set_travel_cost(real_t p_travel_cost); real_t get_travel_cost() const { return travel_cost; } - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; }; #endif // NAVIGATION_LINK_3D_H diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index 9b49238333..07d8cd9289 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -126,8 +126,8 @@ NavigationObstacle3D::~NavigationObstacle3D() { agent = RID(); // Pointless } -TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationObstacle3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node3D>(get_parent())) { warnings.push_back(RTR("The NavigationObstacle3D only serves to provide collision avoidance to a Node3D inheriting parent object.")); diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index 24caf50680..f242d2f99e 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -72,7 +72,7 @@ public: return radius; } - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; private: void initialize_agent(); diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 049ca4c8a0..bfc4353138 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -260,8 +260,8 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) { emit_signal(SNAME("bake_finished")); } -TypedArray<String> NavigationRegion3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray NavigationRegion3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { if (!navmesh.is_valid()) { diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index ba326abb46..7d16d81d77 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -90,7 +90,7 @@ public: void bake_navigation_mesh(bool p_on_thread); void _bake_finished(Ref<NavigationMesh> p_nav_mesh); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; NavigationRegion3D(); ~NavigationRegion3D(); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 59ec036558..ebf26996dd 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -1037,6 +1037,7 @@ void Node3D::_bind_methods() { BIND_CONSTANT(NOTIFICATION_ENTER_WORLD); BIND_CONSTANT(NOTIFICATION_EXIT_WORLD); BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); + BIND_CONSTANT(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); BIND_ENUM_CONSTANT(ROTATION_EDIT_MODE_EULER); BIND_ENUM_CONSTANT(ROTATION_EDIT_MODE_QUATERNION); diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp index 015cb9a21d..4e1ed5654a 100644 --- a/scene/3d/occluder_instance_3d.cpp +++ b/scene/3d/occluder_instance_3d.cpp @@ -682,8 +682,8 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake_scene(Node *p_from_node, return BAKE_ERROR_OK; } -TypedArray<String> OccluderInstance3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray OccluderInstance3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!bool(GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling"))) { warnings.push_back(RTR("Occlusion culling is disabled in the Project Settings, which means occlusion culling won't be performed in the root viewport.\nTo resolve this, open the Project Settings and enable Rendering > Occlusion Culling > Use Occlusion Culling.")); diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h index 69a80e63fc..f507fee024 100644 --- a/scene/3d/occluder_instance_3d.h +++ b/scene/3d/occluder_instance_3d.h @@ -181,7 +181,7 @@ protected: static void _bind_methods(); public: - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; enum BakeError { BAKE_ERROR_OK, diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 2d1f4a579b..123a044b84 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -341,8 +341,8 @@ void PathFollow3D::_validate_property(PropertyInfo &p_property) const { } } -TypedArray<String> PathFollow3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray PathFollow3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { if (!Object::cast_to<Path3D>(get_parent())) { diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 45fa2c8917..b161b12185 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -112,7 +112,7 @@ public: void set_cubic_interpolation(bool p_enable); bool get_cubic_interpolation() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; PathFollow3D() {} }; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index fc13275a7d..0eefb45c04 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); @@ -91,10 +91,10 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } -Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, int p_max_collisions) { +Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_distance, p_margin); parameters.max_collisions = p_max_collisions; - parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery. + parameters.recovery_as_collision = p_recovery_as_collision; PhysicsServer3D::MotionResult result; @@ -169,7 +169,7 @@ bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_ return colliding; } -bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) { +bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer3D::MotionResult *r = nullptr; @@ -182,7 +182,7 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distan } PhysicsServer3D::MotionParameters parameters(p_from, p_distance, p_margin); - parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery. + parameters.recovery_as_collision = p_recovery_as_collision; return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r); } @@ -972,10 +972,10 @@ TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const { return ret; } -TypedArray<String> RigidBody3D::get_configuration_warnings() const { +PackedStringArray RigidBody3D::get_configuration_warnings() const { Transform3D t = get_transform(); - TypedArray<String> warnings = Node::get_configuration_warnings(); + PackedStringArray warnings = Node::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.")); @@ -1200,7 +1200,6 @@ bool CharacterBody3D::move_and_slide() { if (!current_platform_velocity.is_zero_approx()) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. parameters.exclude_bodies.insert(platform_rid); if (platform_object_id.is_valid()) { @@ -1264,8 +1263,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.max_collisions = 4; - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.max_collisions = 6; // There can be 4 collisions between 2 walls + 2 more for the floor. PhysicsServer3D::MotionResult result; bool collided = move_and_collide(parameters, result, false, !sliding_enabled); @@ -1510,7 +1508,6 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { bool first_slide = true; for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. PhysicsServer3D::MotionResult result; bool collided = move_and_collide(parameters, result, false, false); @@ -1565,7 +1562,7 @@ void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_ PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); parameters.max_collisions = 4; - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection. parameters.collide_separation_ray = true; PhysicsServer3D::MotionResult result; @@ -1601,7 +1598,7 @@ bool CharacterBody3D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_f PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); parameters.max_collisions = 4; - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.recovery_as_collision = true; // Report margin recovery as collision to improve floor detection. parameters.collide_separation_ray = true; PhysicsServer3D::MotionResult result; diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 184d8b00d0..4b874b91d9 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -50,11 +50,11 @@ protected: uint16_t locked_axis = 0; - Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1); + Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); public: bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1); + bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; @@ -325,7 +325,7 @@ public: void set_constant_torque(const Vector3 &p_torque); Vector3 get_constant_torque() const; - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; RigidBody3D(); ~RigidBody3D(); diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 9979052385..ff05e88241 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -178,8 +178,8 @@ void RemoteTransform3D::force_update_cache() { _update_cache(); } -TypedArray<String> RemoteTransform3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray RemoteTransform3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) { warnings.push_back(RTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.")); diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h index ab134c1261..cc83661f26 100644 --- a/scene/3d/remote_transform_3d.h +++ b/scene/3d/remote_transform_3d.h @@ -70,7 +70,7 @@ public: void force_update_cache(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; RemoteTransform3D(); }; diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp index a2fecf9c31..e7d1a8ec7d 100644 --- a/scene/3d/shape_cast_3d.cpp +++ b/scene/3d/shape_cast_3d.cpp @@ -167,8 +167,8 @@ void ShapeCast3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color"); } -TypedArray<String> ShapeCast3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node3D::get_configuration_warnings(); +PackedStringArray ShapeCast3D::get_configuration_warnings() const { + PackedStringArray warnings = Node3D::get_configuration_warnings(); if (shape.is_null()) { warnings.push_back(RTR("This node cannot interact with other objects unless a Shape3D is assigned.")); diff --git a/scene/3d/shape_cast_3d.h b/scene/3d/shape_cast_3d.h index 5bda15e4b0..2526d8d32c 100644 --- a/scene/3d/shape_cast_3d.h +++ b/scene/3d/shape_cast_3d.h @@ -136,7 +136,7 @@ public: void remove_exception(const Object *p_object); void clear_exceptions(); - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; }; #endif // SHAPE_CAST_3D_H diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index e04e1866db..85b2c5154b 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -45,7 +45,6 @@ void SkinReference::_skin_changed() { } void SkinReference::_bind_methods() { - ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed); ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton); ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin); } @@ -1007,7 +1006,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { skin_bindings.insert(skin_ref.operator->()); - skin_ref->skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed")); + skin_ref->skin->connect("changed", callable_mp(skin_ref.operator->(), &SkinReference::_skin_changed)); _make_dirty(); // Skin needs to be updated, so update skeleton. diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 5e49dfa1f4..c2e9cfcced 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -51,12 +51,14 @@ class SkinReference : public RefCounted { uint64_t skeleton_version = 0; Vector<uint32_t> skin_bone_indices; uint32_t *skin_bone_indices_ptrs = nullptr; - void _skin_changed(); protected: static void _bind_methods(); public: + // Public for use with callable_mp. + void _skin_changed(); + RID get_skeleton() const; Ref<Skin> get_skin() const; ~SkinReference(); diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index 47858b372c..2466b71aea 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -384,8 +384,8 @@ void SoftBody3D::_bind_methods() { BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); } -TypedArray<String> SoftBody3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray SoftBody3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (mesh.is_null()) { warnings.push_back(RTR("This body will be ignored until you set a mesh.")); diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index 40f3d6f1f4..9ec1f18396 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -125,7 +125,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; public: RID get_physics_rid() const { return physics_rid; } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 7a89bf81bb..4b83bcdfc4 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -87,6 +87,182 @@ void SpriteBase3D::_notification(int p_what) { } } +void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect) { + ERR_FAIL_COND(p_texture.is_null()); + + Rect2 final_rect; + Rect2 final_src_rect; + if (!p_texture->get_rect_region(p_dst_rect, p_src_rect, final_rect, final_src_rect)) { + return; + } + + if (final_rect.size.x == 0 || final_rect.size.y == 0) { + return; + } + + // 2D: 3D plane (axes match exactly when `axis == Vector3::AXIS_Z`): + // -X+ -X+ + // - + + // Y +--------+ +--------+ +--------+ Y +--------+ + // + | +--+ | | | (2) | | - | 0--1 | + // | |ab| | (1) | +--+ | (3) | 3--2 | | |ab| | + // | |cd| | --> | |ab| | --> | |cd| | <==> | |cd| | + // | +--+ | | |cd| | | |ab| | | 3--2 | + // | | | +--+ | | 0--1 | | | + // +--------+ +--------+ +--------+ +--------+ + + // (1) Y-wise shift `final_rect` within `p_dst_rect` so after inverting Y + // axis distances between top/bottom borders will be preserved (so for + // example AtlasTextures with vertical margins will look the same in 2D/3D). + final_rect.position.y = (p_dst_rect.position.y + p_dst_rect.size.y) - ((final_rect.position.y + final_rect.size.y) - p_dst_rect.position.y); + + Color color = _get_color_accum(); + + real_t pixel_size = get_pixel_size(); + + // (2) Order vertices (0123) bottom-top in 2D / top-bottom in 3D. + Vector2 vertices[4] = { + (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, + (final_rect.position + final_rect.size) * pixel_size, + (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, + final_rect.position * pixel_size, + }; + + Vector2 src_tsize = p_texture->get_size(); + + // Properly setup UVs for impostor textures (AtlasTexture). + Ref<AtlasTexture> atlas_tex = p_texture; + if (atlas_tex != nullptr) { + src_tsize[0] = atlas_tex->get_atlas()->get_width(); + src_tsize[1] = atlas_tex->get_atlas()->get_height(); + } + + // (3) Assign UVs (abcd) according to the vertices order (bottom-top in 2D / top-bottom in 3D). + Vector2 uvs[4] = { + final_src_rect.position / src_tsize, + (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize, + (final_src_rect.position + final_src_rect.size) / src_tsize, + (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize, + }; + + if (is_flipped_h()) { + SWAP(uvs[0], uvs[1]); + SWAP(uvs[2], uvs[3]); + } + + if (is_flipped_v()) { + SWAP(uvs[0], uvs[3]); + SWAP(uvs[1], uvs[2]); + } + + Vector3 normal; + int axis = get_axis(); + normal[axis] = 1.0; + + Plane tangent; + if (axis == Vector3::AXIS_X) { + tangent = Plane(0, 0, -1, 1); + } else { + tangent = Plane(1, 0, 0, 1); + } + + int x_axis = ((axis + 1) % 3); + int y_axis = ((axis + 2) % 3); + + if (axis != Vector3::AXIS_Z) { + SWAP(x_axis, y_axis); + + for (int i = 0; i < 4; i++) { + //uvs[i] = Vector2(1.0,1.0)-uvs[i]; + //SWAP(vertices[i].x,vertices[i].y); + if (axis == Vector3::AXIS_Y) { + vertices[i].y = -vertices[i].y; + } else if (axis == Vector3::AXIS_X) { + vertices[i].x = -vertices[i].x; + } + } + } + + AABB aabb; + + // Everything except position and UV is compressed. + uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); + uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); + + uint32_t v_normal; + { + Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + Vector2 res = n.octahedron_encode(); + uint32_t value = 0; + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; + + v_normal = value; + } + uint32_t v_tangent; + { + Plane t = tangent; + Vector2 res = t.normal.octahedron_tangent_encode(t.d); + uint32_t value = 0; + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; + + v_tangent = value; + } + + uint8_t v_color[4] = { + uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0)) + }; + + for (int i = 0; i < 4; i++) { + Vector3 vtx; + vtx[x_axis] = vertices[i][0]; + vtx[y_axis] = vertices[i][1]; + if (i == 0) { + aabb.position = vtx; + aabb.size = Vector3(); + } else { + aabb.expand_to(vtx); + } + + float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y }; + memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8); + + float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z }; + + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3); + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); + memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4); + } + + RID mesh = get_mesh(); + RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer); + RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer); + + RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb); + set_aabb(aabb); + + RID shader_rid; + StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid); + if (last_shader != shader_rid) { + RS::get_singleton()->material_set_shader(get_material(), shader_rid); + last_shader = shader_rid; + } + if (last_texture != p_texture->get_rid()) { + RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid()); + last_texture = p_texture->get_rid(); + } + if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) { + RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority()); + RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material()); + } +} + void SpriteBase3D::set_centered(bool p_center) { centered = p_center; _queue_redraw(); @@ -447,7 +623,7 @@ void Sprite3D::_draw() { if (get_base() != get_mesh()) { set_base(get_mesh()); } - if (!texture.is_valid()) { + if (texture.is_null()) { set_base(RID()); return; } @@ -464,171 +640,17 @@ void Sprite3D::_draw() { } Size2 frame_size = base_rect.size / Size2(hframes, vframes); - Point2 frame_offset = Point2(frame % hframes, frame / hframes); - frame_offset *= frame_size; + Point2 frame_offset = Point2(frame % hframes, frame / hframes) * frame_size; - Point2 dest_offset = get_offset(); + Point2 dst_offset = get_offset(); if (is_centered()) { - dest_offset -= frame_size / 2; + dst_offset -= frame_size / 2.0f; } Rect2 src_rect(base_rect.position + frame_offset, frame_size); - Rect2 final_dst_rect(dest_offset, frame_size); - Rect2 final_rect; - Rect2 final_src_rect; - if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect)) { - return; - } - - if (final_rect.size.x == 0 || final_rect.size.y == 0) { - return; - } - - Color color = _get_color_accum(); - - real_t pixel_size = get_pixel_size(); - - Vector2 vertices[4] = { - - (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, - (final_rect.position + final_rect.size) * pixel_size, - (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, - final_rect.position * pixel_size, - - }; - - Vector2 src_tsize = tsize; - - // Properly setup UVs for impostor textures (AtlasTexture). - Ref<AtlasTexture> atlas_tex = texture; - if (atlas_tex != nullptr) { - src_tsize[0] = atlas_tex->get_atlas()->get_width(); - src_tsize[1] = atlas_tex->get_atlas()->get_height(); - } - - Vector2 uvs[4] = { - final_src_rect.position / src_tsize, - (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize, - (final_src_rect.position + final_src_rect.size) / src_tsize, - (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize, - }; - - if (is_flipped_h()) { - SWAP(uvs[0], uvs[1]); - SWAP(uvs[2], uvs[3]); - } - - if (is_flipped_v()) { - SWAP(uvs[0], uvs[3]); - SWAP(uvs[1], uvs[2]); - } - - Vector3 normal; - int axis = get_axis(); - normal[axis] = 1.0; - - Plane tangent; - if (axis == Vector3::AXIS_X) { - tangent = Plane(0, 0, -1, 1); - } else { - tangent = Plane(1, 0, 0, 1); - } - - int x_axis = ((axis + 1) % 3); - int y_axis = ((axis + 2) % 3); - - if (axis != Vector3::AXIS_Z) { - SWAP(x_axis, y_axis); - - for (int i = 0; i < 4; i++) { - //uvs[i] = Vector2(1.0,1.0)-uvs[i]; - //SWAP(vertices[i].x,vertices[i].y); - if (axis == Vector3::AXIS_Y) { - vertices[i].y = -vertices[i].y; - } else if (axis == Vector3::AXIS_X) { - vertices[i].x = -vertices[i].x; - } - } - } - - AABB aabb; - - // Everything except position and UV is compressed. - uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); - uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); + Rect2 dst_rect(dst_offset, frame_size); - uint32_t v_normal; - { - Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - - Vector2 res = n.octahedron_encode(); - uint32_t value = 0; - value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); - value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; - - v_normal = value; - } - uint32_t v_tangent; - { - Plane t = tangent; - Vector2 res = t.normal.octahedron_tangent_encode(t.d); - uint32_t value = 0; - value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); - value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; - - v_tangent = value; - } - - uint8_t v_color[4] = { - uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)), - uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)), - uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)), - uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0)) - }; - - for (int i = 0; i < 4; i++) { - Vector3 vtx; - vtx[x_axis] = vertices[i][0]; - vtx[y_axis] = vertices[i][1]; - if (i == 0) { - aabb.position = vtx; - aabb.size = Vector3(); - } else { - aabb.expand_to(vtx); - } - - float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y }; - memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8); - - float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z }; - - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3); - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); - memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4); - } - - RID mesh = get_mesh(); - RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer); - RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer); - - RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb); - set_aabb(aabb); - - RID shader_rid; - StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid); - if (last_shader != shader_rid) { - RS::get_singleton()->material_set_shader(get_material(), shader_rid); - last_shader = shader_rid; - } - if (last_texture != texture->get_rid()) { - RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid()); - last_texture = texture->get_rid(); - } - if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) { - RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority()); - RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material()); - } + draw_texture_rect(texture, dst_rect, src_rect); } void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) { @@ -807,15 +829,7 @@ void AnimatedSprite3D::_draw() { set_base(get_mesh()); } - if (frames.is_null()) { - return; - } - - if (frame < 0) { - return; - } - - if (!frames->has_animation(animation)) { + if (frames.is_null() || !frames->has_animation(animation)) { return; } @@ -839,158 +853,7 @@ void AnimatedSprite3D::_draw() { Rect2 dst_rect(ofs, tsize); - Rect2 final_rect; - Rect2 final_src_rect; - if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect)) { - return; - } - - if (final_rect.size.x == 0 || final_rect.size.y == 0) { - return; - } - - Color color = _get_color_accum(); - - real_t pixel_size = get_pixel_size(); - - Vector2 vertices[4] = { - - (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, - (final_rect.position + final_rect.size) * pixel_size, - (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, - final_rect.position * pixel_size, - - }; - - Vector2 src_tsize = tsize; - - // Properly setup UVs for impostor textures (AtlasTexture). - Ref<AtlasTexture> atlas_tex = texture; - if (atlas_tex != nullptr) { - src_tsize[0] = atlas_tex->get_atlas()->get_width(); - src_tsize[1] = atlas_tex->get_atlas()->get_height(); - } - - Vector2 uvs[4] = { - final_src_rect.position / src_tsize, - (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize, - (final_src_rect.position + final_src_rect.size) / src_tsize, - (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize, - }; - - if (is_flipped_h()) { - SWAP(uvs[0], uvs[1]); - SWAP(uvs[2], uvs[3]); - } - if (is_flipped_v()) { - SWAP(uvs[0], uvs[3]); - SWAP(uvs[1], uvs[2]); - } - - Vector3 normal; - int axis = get_axis(); - normal[axis] = 1.0; - - Plane tangent; - if (axis == Vector3::AXIS_X) { - tangent = Plane(0, 0, -1, -1); - } else { - tangent = Plane(1, 0, 0, -1); - } - - int x_axis = ((axis + 1) % 3); - int y_axis = ((axis + 2) % 3); - - if (axis != Vector3::AXIS_Z) { - SWAP(x_axis, y_axis); - - for (int i = 0; i < 4; i++) { - //uvs[i] = Vector2(1.0,1.0)-uvs[i]; - //SWAP(vertices[i].x,vertices[i].y); - if (axis == Vector3::AXIS_Y) { - vertices[i].y = -vertices[i].y; - } else if (axis == Vector3::AXIS_X) { - vertices[i].x = -vertices[i].x; - } - } - } - - AABB aabb; - - // Everything except position and UV is compressed. - uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); - uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); - - uint32_t v_normal; - { - Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - - Vector2 res = n.octahedron_encode(); - uint32_t value = 0; - value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); - value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; - - v_normal = value; - } - uint32_t v_tangent; - { - Plane t = tangent; - Vector2 res = t.normal.octahedron_tangent_encode(t.d); - uint32_t value = 0; - value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); - value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; - v_tangent = value; - } - - uint8_t v_color[4] = { - uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)), - uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)), - uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)), - uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0)) - }; - - for (int i = 0; i < 4; i++) { - Vector3 vtx; - vtx[x_axis] = vertices[i][0]; - vtx[y_axis] = vertices[i][1]; - if (i == 0) { - aabb.position = vtx; - aabb.size = Vector3(); - } else { - aabb.expand_to(vtx); - } - - float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y }; - memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8); - - float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z }; - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3); - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); - memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4); - } - - RID mesh = get_mesh(); - RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer); - RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer); - - RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb); - set_aabb(aabb); - - RID shader_rid; - StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid); - if (last_shader != shader_rid) { - RS::get_singleton()->material_set_shader(get_material(), shader_rid); - last_shader = shader_rid; - } - if (last_texture != texture->get_rid()) { - RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid()); - last_texture = texture->get_rid(); - } - if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) { - RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority()); - RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material()); - } + draw_texture_rect(texture, dst_rect, src_rect); } void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { @@ -1050,29 +913,22 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { void AnimatedSprite3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_INTERNAL_PROCESS: { - if (frames.is_null()) { - return; - } - if (!frames->has_animation(animation)) { + if (frames.is_null() || !frames->has_animation(animation)) { return; } - if (frame < 0) { - return; + + double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale); + if (speed == 0) { + return; // Do nothing. } + int last_frame = frames->get_frame_count(animation) - 1; double remaining = get_process_delta_time(); - while (remaining) { - double speed = frames->get_animation_speed(animation) * speed_scale; - if (speed == 0) { - return; // Do nothing. - } - if (timeout <= 0) { timeout = _get_frame_duration(); - int last_frame = frames->get_frame_count(animation) - 1; - if (!backwards) { + if (!playing_backwards) { // Forward. if (frame >= last_frame) { if (frames->get_animation_loop(animation)) { @@ -1177,9 +1033,14 @@ int AnimatedSprite3D::get_frame() const { } void AnimatedSprite3D::set_speed_scale(double p_speed_scale) { + if (speed_scale == p_speed_scale) { + return; + } + double elapsed = _get_frame_duration() - timeout; - speed_scale = MAX(p_speed_scale, 0.0f); + speed_scale = p_speed_scale; + playing_backwards = signbit(speed_scale) != backwards; // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed. _reset_timeout(); @@ -1191,7 +1052,10 @@ double AnimatedSprite3D::get_speed_scale() const { } Rect2 AnimatedSprite3D::get_item_rect() const { - if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { + if (frames.is_null() || !frames->has_animation(animation)) { + return Rect2(0, 0, 1, 1); + } + if (frame < 0 || frame >= frames->get_frame_count(animation)) { return Rect2(0, 0, 1, 1); } @@ -1236,12 +1100,13 @@ bool AnimatedSprite3D::is_playing() const { return playing; } -void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) { +void AnimatedSprite3D::play(const StringName &p_animation, bool p_backwards) { backwards = p_backwards; + playing_backwards = signbit(speed_scale) != backwards; if (p_animation) { set_animation(p_animation); - if (frames.is_valid() && backwards && get_frame() == 0) { + if (frames.is_valid() && playing_backwards && get_frame() == 0) { set_frame(frames->get_frame_count(p_animation) - 1); } } @@ -1256,7 +1121,7 @@ void AnimatedSprite3D::stop() { double AnimatedSprite3D::_get_frame_duration() { if (frames.is_valid() && frames->has_animation(animation)) { - double speed = frames->get_animation_speed(animation) * speed_scale; + double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale); if (speed > 0) { return 1.0 / speed; } @@ -1291,8 +1156,8 @@ StringName AnimatedSprite3D::get_animation() const { return animation; } -TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const { - TypedArray<String> warnings = SpriteBase3D::get_configuration_warnings(); +PackedStringArray AnimatedSprite3D::get_configuration_warnings() const { + PackedStringArray warnings = SpriteBase3D::get_configuration_warnings(); if (frames.is_null()) { warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.")); } diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index e6a546a76d..edc48c7b71 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -80,6 +80,9 @@ private: RID mesh; RID material; + RID last_shader; + RID last_texture; + bool flags[FLAG_MAX] = {}; AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED; StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED; @@ -94,6 +97,7 @@ protected: void _notification(int p_what); static void _bind_methods(); virtual void _draw() = 0; + void draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect); _FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; } _FORCE_INLINE_ RID &get_mesh() { return mesh; } _FORCE_INLINE_ RID &get_material() { return material; } @@ -167,9 +171,6 @@ class Sprite3D : public SpriteBase3D { int vframes = 1; int hframes = 1; - RID last_shader; - RID last_texture; - protected: virtual void _draw() override; static void _bind_methods(); @@ -209,6 +210,7 @@ class AnimatedSprite3D : public SpriteBase3D { Ref<SpriteFrames> frames; bool playing = false; + bool playing_backwards = false; bool backwards = false; StringName animation = "default"; int frame = 0; @@ -224,9 +226,6 @@ class AnimatedSprite3D : public SpriteBase3D { double _get_frame_duration(); void _reset_timeout(); - RID last_shader; - RID last_texture; - protected: virtual void _draw() override; static void _bind_methods(); @@ -237,7 +236,7 @@ public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); Ref<SpriteFrames> get_sprite_frames() const; - void play(const StringName &p_animation = StringName(), const bool p_backwards = false); + void play(const StringName &p_animation = StringName(), bool p_backwards = false); void stop(); void set_playing(bool p_playing); @@ -254,7 +253,7 @@ public: virtual Rect2 get_item_rect() const override; - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; AnimatedSprite3D(); diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index d61b49eaa7..36b5e61f45 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -105,8 +105,8 @@ void VehicleWheel3D::_notification(int p_what) { } } -TypedArray<String> VehicleWheel3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray VehicleWheel3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<VehicleBody3D>(get_parent())) { warnings.push_back(RTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.")); diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h index 5c4f4beaea..a6a49ee88a 100644 --- a/scene/3d/vehicle_body_3d.h +++ b/scene/3d/vehicle_body_3d.h @@ -147,7 +147,7 @@ public: void set_steering(real_t p_steering); real_t get_steering() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; VehicleWheel3D(); }; diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index db9f68544b..e93ad5ecbf 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -385,8 +385,8 @@ bool GeometryInstance3D::is_ignoring_occlusion_culling() { return ignore_occlusion_culling; } -TypedArray<String> GeometryInstance3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray GeometryInstance3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!Math::is_zero_approx(visibility_range_end) && visibility_range_end <= visibility_range_begin) { warnings.push_back(RTR("The GeometryInstance3D visibility range's End distance is set to a non-zero value, but is lower than the Begin distance.\nThis means the GeometryInstance3D will never be visible.\nTo resolve this, set the End distance to 0 or to a value greater than the Begin distance.")); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 100d8d8836..4755545516 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -186,7 +186,7 @@ public: void set_ignore_occlusion_culling(bool p_enabled); bool is_ignoring_occlusion_culling(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; GeometryInstance3D(); virtual ~GeometryInstance3D(); }; diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index c97af087bf..1b1ac32207 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -468,8 +468,8 @@ AABB VoxelGI::get_aabb() const { return AABB(-extents, extents * 2); } -TypedArray<String> VoxelGI::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray VoxelGI::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { warnings.push_back(RTR("VoxelGIs are not supported by the OpenGL video driver.\nUse a LightmapGI instead.")); diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h index b31ae4cd95..fc10091d4f 100644 --- a/scene/3d/voxel_gi.h +++ b/scene/3d/voxel_gi.h @@ -157,7 +157,7 @@ public: virtual AABB get_aabb() const override; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; VoxelGI(); ~VoxelGI(); diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index ae7d79e8b0..6cc5e9ef20 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -135,8 +135,8 @@ Ref<CameraAttributes> WorldEnvironment::get_camera_attributes() const { return camera_attributes; } -TypedArray<String> WorldEnvironment::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray WorldEnvironment::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!environment.is_valid() && !camera_attributes.is_valid()) { warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Attributes\" property to contain a CameraAttributes resource, or both.")); diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index 07f243c750..cc46a06b4c 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -55,7 +55,7 @@ public: void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); Ref<CameraAttributes> get_camera_attributes() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; WorldEnvironment(); }; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index de765d7ccb..4401d22f30 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -88,8 +88,8 @@ void XRCamera3D::_pose_changed(const Ref<XRPose> &p_pose) { } } -TypedArray<String> XRCamera3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray XRCamera3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { // must be child node of XROrigin3D! @@ -414,8 +414,8 @@ XRNode3D::~XRNode3D() { xr_server->disconnect("tracker_removed", callable_mp(this, &XRNode3D::_removed_tracker)); } -TypedArray<String> XRNode3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray XRNode3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { // must be child node of XROrigin! @@ -582,8 +582,8 @@ Plane XRAnchor3D::get_plane() const { //////////////////////////////////////////////////////////////////////////////////////////////////// -TypedArray<String> XROrigin3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray XROrigin3D::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { if (tracked_camera == nullptr) { diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 312bef7856..ef846cc3a3 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -55,7 +55,7 @@ protected: void _pose_changed(const Ref<XRPose> &p_pose); public: - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override; virtual Point2 unproject_position(const Vector3 &p_pos) const override; @@ -107,7 +107,7 @@ public: Ref<XRPose> get_pose(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; XRNode3D(); ~XRNode3D(); @@ -187,7 +187,7 @@ protected: static void _bind_methods(); public: - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_tracked_camera(XRCamera3D *p_tracked_camera); XRCamera3D *get_tracked_camera() const; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 99f17a1eef..1efbaacb3b 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -1175,6 +1175,7 @@ void AnimationNodeBlendTree::_tree_changed() { void AnimationNodeBlendTree::_node_changed(const StringName &p_node) { ERR_FAIL_COND(!nodes.has(p_node)); nodes[p_node].connections.resize(nodes[p_node].node->get_input_count()); + emit_signal(SNAME("node_changed"), p_node); } void AnimationNodeBlendTree::_bind_methods() { @@ -1200,6 +1201,8 @@ void AnimationNodeBlendTree::_bind_methods() { BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT); BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE); BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS); + + ADD_SIGNAL(MethodInfo("node_changed", PropertyInfo(Variant::STRING_NAME, "node_name"))); } void AnimationNodeBlendTree::_initialize_node_tree() { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 096f4edee2..ce9406883d 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -650,15 +650,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double double c = Math::ease(p_time / first_key_time, transition); Variant first_value = a->track_get_key_value(i, first_key); first_value = _post_process_key_value(a, i, first_value, nc->node); - Variant interp_value; - Variant::interpolate(pa->capture, first_value, c, interp_value); + Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c); if (pa->accum_pass != accum_pass) { ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX); cache_update_prop[cache_update_prop_size++] = pa; pa->value_accum = interp_value; pa->accum_pass = accum_pass; } else { - Variant::interpolate(pa->value_accum, interp_value, p_interp, pa->value_accum); + pa->value_accum = Animation::interpolate_variant(pa->value_accum, interp_value, p_interp); } continue; //handled @@ -679,7 +678,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double pa->value_accum = value; pa->accum_pass = accum_pass; } else { - Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum); + pa->value_accum = Animation::interpolate_variant(pa->value_accum, value, p_interp); } } else if (p_is_current && p_delta != 0) { @@ -1270,6 +1269,8 @@ void AnimationPlayer::_animation_set_cache_update() { // If something was modified or removed, caches need to be cleared clear_caches(); } + + emit_signal(SNAME("animation_list_changed")); } void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) { @@ -2150,6 +2151,7 @@ void AnimationPlayer::_bind_methods() { ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name"))); ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name"))); + ADD_SIGNAL(MethodInfo("animation_list_changed")); ADD_SIGNAL(MethodInfo("caches_cleared")); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index d06324f0aa..bcd52082af 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -847,6 +847,11 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { return true; } +void AnimationTree::_animation_player_changed() { + emit_signal(SNAME("animation_player_changed")); + _clear_caches(); +} + void AnimationTree::_clear_caches() { for (KeyValue<NodePath, TrackCache *> &K : track_cache) { memdelete(K.value); @@ -1378,8 +1383,13 @@ void AnimationTree::_process_graph(double p_delta) { } t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU); } else { - Variant::sub(value, t->init_value, value); - Variant::blend(t->value, value, blend, t->value); + if (t->init_value.get_type() == Variant::BOOL) { + value = Animation::subtract_variant(value.operator real_t(), t->init_value.operator real_t()); + t->value = Animation::blend_variant(t->value.operator real_t(), value.operator real_t(), blend); + } else { + value = Animation::subtract_variant(value, t->init_value); + t->value = Animation::blend_variant(t->value, value, blend); + } } } else { if (blend < CMP_EPSILON) { @@ -1698,7 +1708,11 @@ void AnimationTree::_process_graph(double p_delta) { case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); - t->object->set_indexed(t->subpath, t->value); + if (t->init_value.get_type() == Variant::BOOL) { + t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5); + } else { + t->object->set_indexed(t->subpath, t->value); + } } break; case Animation::TYPE_BEZIER: { @@ -1738,6 +1752,7 @@ void AnimationTree::advance(real_t p_time) { void AnimationTree::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { + _setup_animation_player(); if (last_animation_player.is_valid()) { Object *player = ObjectDB::get_instance(last_animation_player); if (player) { @@ -1770,8 +1785,43 @@ void AnimationTree::_notification(int p_what) { } } +void AnimationTree::_setup_animation_player() { + if (!is_inside_tree()) { + return; + } + + AnimationPlayer *new_player = nullptr; + if (!animation_player.is_empty()) { + new_player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); + if (new_player && !new_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) { + new_player->connect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed)); + } + } + + if (new_player) { + if (!last_animation_player.is_valid()) { + // Animation player set newly. + emit_signal(SNAME("animation_player_changed")); + return; + } else if (last_animation_player == new_player->get_instance_id()) { + // Animation player isn't changed. + return; + } + } else if (!last_animation_player.is_valid()) { + // Animation player is being empty. + return; + } + + AnimationPlayer *old_player = Object::cast_to<AnimationPlayer>(ObjectDB::get_instance(last_animation_player)); + if (old_player && old_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) { + old_player->disconnect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed)); + } + emit_signal(SNAME("animation_player_changed")); +} + void AnimationTree::set_animation_player(const NodePath &p_player) { animation_player = p_player; + _setup_animation_player(); update_configuration_warnings(); } @@ -1799,8 +1849,8 @@ uint64_t AnimationTree::get_last_process_pass() const { return process_pass; } -TypedArray<String> AnimationTree::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray AnimationTree::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!root.is_valid()) { warnings.push_back(RTR("No root AnimationNode for the graph is set.")); @@ -2008,6 +2058,8 @@ void AnimationTree::_bind_methods() { BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); + + ADD_SIGNAL(MethodInfo("animation_player_changed")); } AnimationTree::AnimationTree() { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index ee0c0303dc..fc31c52bc6 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -282,6 +282,8 @@ private: bool cache_valid = false; void _node_removed(Node *p_node); + void _setup_animation_player(); + void _animation_player_changed(); void _clear_caches(); bool _update_caches(AnimationPlayer *player); void _process_graph(double p_delta); @@ -340,7 +342,7 @@ public: void set_advance_expression_base_node(const NodePath &p_advance_expression_base_node); NodePath get_advance_expression_base_node() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; bool is_state_invalid() const; String get_invalid_state_reason() const; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 5b18d4e457..b02f1959b7 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -32,6 +32,7 @@ #include "scene/animation/easing_equations.h" #include "scene/main/node.h" +#include "scene/resources/animation.h" Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = { { &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing. @@ -314,6 +315,7 @@ bool Tween::step(float p_delta) { running = false; dead = true; emit_signal(SNAME("finished")); + break; } else { emit_signal(SNAME("loop_finished"), loops_done); current_step = 0; @@ -375,264 +377,14 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant()); ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant()); -// Helper macro to run equation on sub-elements of the value (e.g. x and y of Vector2). -#define APPLY_EQUATION(element) \ - r.element = run_equation(p_trans, p_ease, p_time, i.element, d.element, p_duration); - - switch (p_initial_val.get_type()) { - case Variant::BOOL: { - return (run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration)) >= 0.5; - } - - case Variant::INT: { - return (int)run_equation(p_trans, p_ease, p_time, (int)p_initial_val, (int)p_delta_val, p_duration); - } - - case Variant::FLOAT: { - return run_equation(p_trans, p_ease, p_time, (real_t)p_initial_val, (real_t)p_delta_val, p_duration); - } - - case Variant::VECTOR2: { - Vector2 i = p_initial_val; - Vector2 d = p_delta_val; - Vector2 r; - - APPLY_EQUATION(x); - APPLY_EQUATION(y); - return r; - } - - case Variant::VECTOR2I: { - Vector2i i = p_initial_val; - Vector2i d = p_delta_val; - Vector2i r; - - APPLY_EQUATION(x); - APPLY_EQUATION(y); - return r; - } - - case Variant::RECT2: { - Rect2 i = p_initial_val; - Rect2 d = p_delta_val; - Rect2 r; - - APPLY_EQUATION(position.x); - APPLY_EQUATION(position.y); - APPLY_EQUATION(size.x); - APPLY_EQUATION(size.y); - return r; - } - - case Variant::RECT2I: { - Rect2i i = p_initial_val; - Rect2i d = p_delta_val; - Rect2i r; - - APPLY_EQUATION(position.x); - APPLY_EQUATION(position.y); - APPLY_EQUATION(size.x); - APPLY_EQUATION(size.y); - return r; - } - - case Variant::VECTOR3: { - Vector3 i = p_initial_val; - Vector3 d = p_delta_val; - Vector3 r; - - APPLY_EQUATION(x); - APPLY_EQUATION(y); - APPLY_EQUATION(z); - return r; - } - - case Variant::VECTOR3I: { - Vector3i i = p_initial_val; - Vector3i d = p_delta_val; - Vector3i r; - - APPLY_EQUATION(x); - APPLY_EQUATION(y); - APPLY_EQUATION(z); - return r; - } - - case Variant::TRANSFORM2D: { - Transform2D i = p_initial_val; - Transform2D d = p_delta_val; - Transform2D r; - - APPLY_EQUATION(columns[0][0]); - APPLY_EQUATION(columns[0][1]); - APPLY_EQUATION(columns[1][0]); - APPLY_EQUATION(columns[1][1]); - APPLY_EQUATION(columns[2][0]); - APPLY_EQUATION(columns[2][1]); - return r; - } - case Variant::VECTOR4: { - Vector4 i = p_initial_val; - Vector4 d = p_delta_val; - Vector4 r; - - APPLY_EQUATION(x); - APPLY_EQUATION(y); - APPLY_EQUATION(z); - APPLY_EQUATION(w); - return r; - } - - case Variant::QUATERNION: { - Quaternion i = p_initial_val; - Quaternion d = p_delta_val; - Quaternion r = i * d; - r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration)); - return r; - } - - case Variant::AABB: { - AABB i = p_initial_val; - AABB d = p_delta_val; - AABB r; - - APPLY_EQUATION(position.x); - APPLY_EQUATION(position.y); - APPLY_EQUATION(position.z); - APPLY_EQUATION(size.x); - APPLY_EQUATION(size.y); - APPLY_EQUATION(size.z); - return r; - } - - case Variant::BASIS: { - Basis i = p_initial_val; - Basis d = p_delta_val; - Basis r; - - APPLY_EQUATION(rows[0][0]); - APPLY_EQUATION(rows[0][1]); - APPLY_EQUATION(rows[0][2]); - APPLY_EQUATION(rows[1][0]); - APPLY_EQUATION(rows[1][1]); - APPLY_EQUATION(rows[1][2]); - APPLY_EQUATION(rows[2][0]); - APPLY_EQUATION(rows[2][1]); - APPLY_EQUATION(rows[2][2]); - return r; - } - - case Variant::TRANSFORM3D: { - Transform3D i = p_initial_val; - Transform3D d = p_delta_val; - Transform3D r; - - APPLY_EQUATION(basis.rows[0][0]); - APPLY_EQUATION(basis.rows[0][1]); - APPLY_EQUATION(basis.rows[0][2]); - APPLY_EQUATION(basis.rows[1][0]); - APPLY_EQUATION(basis.rows[1][1]); - APPLY_EQUATION(basis.rows[1][2]); - APPLY_EQUATION(basis.rows[2][0]); - APPLY_EQUATION(basis.rows[2][1]); - APPLY_EQUATION(basis.rows[2][2]); - APPLY_EQUATION(origin.x); - APPLY_EQUATION(origin.y); - APPLY_EQUATION(origin.z); - return r; - } - - case Variant::COLOR: { - Color i = p_initial_val; - Color d = p_delta_val; - Color r; - - APPLY_EQUATION(r); - APPLY_EQUATION(g); - APPLY_EQUATION(b); - APPLY_EQUATION(a); - return r; - } - - default: { - return p_initial_val; - } - }; -#undef APPLY_EQUATION -} - -Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) { - ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type())); - - switch (p_intial_val.get_type()) { - case Variant::BOOL: { - return (int)p_final_val - (int)p_intial_val; - } - - case Variant::RECT2: { - Rect2 i = p_intial_val; - Rect2 f = p_final_val; - return Rect2(f.position - i.position, f.size - i.size); - } - - case Variant::RECT2I: { - Rect2i i = p_intial_val; - Rect2i f = p_final_val; - return Rect2i(f.position - i.position, f.size - i.size); - } - - case Variant::TRANSFORM2D: { - Transform2D i = p_intial_val; - Transform2D f = p_final_val; - return Transform2D(f.columns[0][0] - i.columns[0][0], - f.columns[0][1] - i.columns[0][1], - f.columns[1][0] - i.columns[1][0], - f.columns[1][1] - i.columns[1][1], - f.columns[2][0] - i.columns[2][0], - f.columns[2][1] - i.columns[2][1]); - } - - case Variant::AABB: { - AABB i = p_intial_val; - AABB f = p_final_val; - return AABB(f.position - i.position, f.size - i.size); - } - - case Variant::BASIS: { - Basis i = p_intial_val; - Basis f = p_final_val; - return Basis(f.rows[0][0] - i.rows[0][0], - f.rows[0][1] - i.rows[0][1], - f.rows[0][2] - i.rows[0][2], - f.rows[1][0] - i.rows[1][0], - f.rows[1][1] - i.rows[1][1], - f.rows[1][2] - i.rows[1][2], - f.rows[2][0] - i.rows[2][0], - f.rows[2][1] - i.rows[2][1], - f.rows[2][2] - i.rows[2][2]); - } - - case Variant::TRANSFORM3D: { - Transform3D i = p_intial_val; - Transform3D f = p_final_val; - return Transform3D(f.basis.rows[0][0] - i.basis.rows[0][0], - f.basis.rows[0][1] - i.basis.rows[0][1], - f.basis.rows[0][2] - i.basis.rows[0][2], - f.basis.rows[1][0] - i.basis.rows[1][0], - f.basis.rows[1][1] - i.basis.rows[1][1], - f.basis.rows[1][2] - i.basis.rows[1][2], - f.basis.rows[2][0] - i.basis.rows[2][0], - f.basis.rows[2][1] - i.basis.rows[2][1], - f.basis.rows[2][2] - i.basis.rows[2][2], - f.origin.x - i.origin.x, - f.origin.y - i.origin.y, - f.origin.z - i.origin.z); - } + // Special case for bool. + if (p_initial_val.get_type() == Variant::BOOL) { + return run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration) >= 0.5; + } - default: { - return Variant::evaluate(Variant::OP_SUBTRACT, p_final_val, p_intial_val); - } - }; + Variant ret = Animation::add_variant(p_initial_val, p_delta_val); + ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration)); + return ret; } void Tween::_bind_methods() { @@ -748,10 +500,10 @@ void PropertyTweener::start() { } if (relative) { - final_val = Variant::evaluate(Variant::Operator::OP_ADD, initial_val, base_final_val); + final_val = Animation::add_variant(initial_val, base_final_val); } - delta_val = tween->calculate_delta_value(initial_val, final_val); + delta_val = Animation::subtract_variant(final_val, initial_val); } bool PropertyTweener::step(float &r_delta) { @@ -973,7 +725,7 @@ void MethodTweener::_bind_methods() { MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) { callback = p_callback; initial_val = p_from; - delta_val = tween->calculate_delta_value(p_from, p_to); + delta_val = Animation::subtract_variant(p_to, p_from); final_val = p_to; duration = p_duration; } diff --git a/scene/animation/tween.h b/scene/animation/tween.h index b57ec2e5e7..da7a8b5d71 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -164,7 +164,6 @@ public: static real_t run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d); static Variant interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, Tween::TransitionType p_trans, Tween::EaseType p_ease); - Variant calculate_delta_value(Variant p_intial_val, Variant p_final_val); bool step(float p_delta); bool can_process(bool p_tree_paused) const; diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index cf467ceafb..3d95677dcf 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -469,7 +469,7 @@ void BaseButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); BIND_ENUM_CONSTANT(DRAW_NORMAL); BIND_ENUM_CONSTANT(DRAW_PRESSED); diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 5512c0f1fd..3c29c37479 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -192,8 +192,8 @@ void Container::_notification(int p_what) { } } -TypedArray<String> Container::get_configuration_warnings() const { - TypedArray<String> warnings = Control::get_configuration_warnings(); +PackedStringArray Container::get_configuration_warnings() const { + PackedStringArray warnings = Control::get_configuration_warnings(); if (get_class() == "Container" && get_script().is_null()) { warnings.push_back(RTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead.")); diff --git a/scene/gui/container.h b/scene/gui/container.h index 9ec4ad3200..21bdb95186 100644 --- a/scene/gui/container.h +++ b/scene/gui/container.h @@ -63,7 +63,7 @@ public: virtual Vector<int> get_allowed_size_flags_horizontal() const; virtual Vector<int> get_allowed_size_flags_vertical() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; Container(); }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 347fe9aa11..ae94be8437 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -213,8 +213,8 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List } } -TypedArray<String> Control::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray Control::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (data.mouse_filter == MOUSE_FILTER_IGNORE && !data.tooltip.is_empty()) { warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\".")); diff --git a/scene/gui/control.h b/scene/gui/control.h index 38cafd835a..ee6443c81c 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -387,7 +387,7 @@ public: // Editor integration. virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; virtual bool is_text_field() const; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 5a0236268b..7295ab9e9d 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -190,8 +190,8 @@ void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) { ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2); } -TypedArray<String> GraphEdit::get_configuration_warnings() const { - TypedArray<String> warnings = Control::get_configuration_warnings(); +PackedStringArray GraphEdit::get_configuration_warnings() const { + PackedStringArray warnings = Control::get_configuration_warnings(); warnings.push_back(RTR("Please be aware that GraphEdit and GraphNode will undergo extensive refactoring in a future beta version involving compatibility-breaking API changes.")); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 0fe9e7c555..101087bdbd 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -287,7 +287,7 @@ protected: GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int); public: - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index d6bf84ea5a..75592a1b99 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -703,7 +703,7 @@ void MenuBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); ADD_GROUP("BiDi", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 1eb412abaf..2d2b3e413d 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -30,8 +30,8 @@ #include "range.h" -TypedArray<String> Range::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray Range::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (shared->exp_ratio && shared->min <= 0) { warnings.push_back(RTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0.")); diff --git a/scene/gui/range.h b/scene/gui/range.h index 87bd0d88af..19452243cf 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -100,7 +100,7 @@ public: void share(Range *p_range); void unshare(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; Range(); ~Range(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 64a0402149..ef0172c612 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -965,17 +965,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o uint32_t gl = glyphs[i].index; uint16_t gl_fl = glyphs[i].flags; uint8_t gl_cn = glyphs[i].count; - bool cprev = false; + bool cprev_cluster = false; + bool cprev_conn = false; if (gl_cn == 0) { // Parts of the same cluster, always connected. - cprev = true; + cprev_cluster = true; } if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected. if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) { - cprev = true; + cprev_conn = true; } } else { if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) { - cprev = true; + cprev_conn = true; } } @@ -994,6 +995,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o for (int j = 0; j < fx_stack.size(); j++) { ItemFX *item_fx = fx_stack[j]; + bool cn = cprev_cluster || (cprev_conn && item_fx->connected); + if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx); @@ -1024,7 +1027,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (item_fx->type == ITEM_SHAKE) { ItemShake *item_shake = static_cast<ItemShake *>(item_fx); - if (!cprev) { + if (!cn) { uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start); uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start); uint64_t max_rand = 2147483647; @@ -1038,7 +1041,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (item_fx->type == ITEM_WAVE) { ItemWave *item_wave = static_cast<ItemWave *>(item_fx); - if (!cprev) { + if (!cn) { double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_wave->amplitude / 10.0f); item_wave->prev_off = Point2(0, 1) * value; } @@ -1046,7 +1049,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (item_fx->type == ITEM_TORNADO) { ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx); - if (!cprev) { + if (!cn) { double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius); double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius); item_tornado->prev_off = Point2(torn_x, torn_y); @@ -1181,17 +1184,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o uint32_t gl = glyphs[i].index; uint16_t gl_fl = glyphs[i].flags; uint8_t gl_cn = glyphs[i].count; - bool cprev = false; + bool cprev_cluster = false; + bool cprev_conn = false; if (gl_cn == 0) { // Parts of the same grapheme cluster, always connected. - cprev = true; + cprev_cluster = true; } if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected. if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) { - cprev = true; + cprev_conn = true; } } else { if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) { - cprev = true; + cprev_conn = true; } } @@ -1209,6 +1213,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o for (int j = 0; j < fx_stack.size(); j++) { ItemFX *item_fx = fx_stack[j]; + bool cn = cprev_cluster || (cprev_conn && item_fx->connected); + if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx); @@ -1239,7 +1245,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (item_fx->type == ITEM_SHAKE) { ItemShake *item_shake = static_cast<ItemShake *>(item_fx); - if (!cprev) { + if (!cn) { uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start); uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start); uint64_t max_rand = 2147483647; @@ -1253,7 +1259,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (item_fx->type == ITEM_WAVE) { ItemWave *item_wave = static_cast<ItemWave *>(item_fx); - if (!cprev) { + if (!cn) { double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f); item_wave->prev_off = Point2(0, 1) * value; } @@ -1261,7 +1267,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (item_fx->type == ITEM_TORNADO) { ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx); - if (!cprev) { + if (!cn) { double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius); double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius); item_tornado->prev_off = Point2(torn_x, torn_y); @@ -2188,6 +2194,30 @@ RichTextLabel::ItemFont *RichTextLabel::_find_font(Item *p_item) { while (fontitem) { if (fontitem->type == ITEM_FONT) { ItemFont *fi = static_cast<ItemFont *>(fontitem); + switch (fi->def_font) { + case NORMAL_FONT: { + fi->font = theme_cache.normal_font; + fi->font_size = theme_cache.normal_font_size; + } break; + case BOLD_FONT: { + fi->font = theme_cache.bold_font; + fi->font_size = theme_cache.bold_font_size; + } break; + case ITALICS_FONT: { + fi->font = theme_cache.italics_font; + fi->font_size = theme_cache.italics_font_size; + } break; + case BOLD_ITALICS_FONT: { + fi->font = theme_cache.bold_italics_font; + fi->font_size = theme_cache.bold_italics_font_size; + } break; + case MONO_FONT: { + fi->font = theme_cache.mono_font; + fi->font_size = theme_cache.mono_font_size; + } break; + default: { + } break; + } return fi; } @@ -3004,6 +3034,17 @@ void RichTextLabel::push_dropcap(const String &p_string, const Ref<Font> &p_font _add_item(item, false); } +void RichTextLabel::_push_def_font(DefaultFont p_font) { + _stop_thread(); + MutexLock data_lock(data_mutex); + + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemFont *item = memnew(ItemFont); + + item->def_font = p_font; + _add_item(item, true); +} + void RichTextLabel::push_font(const Ref<Font> &p_font, int p_size) { _stop_thread(); MutexLock data_lock(data_mutex); @@ -3020,31 +3061,31 @@ void RichTextLabel::push_font(const Ref<Font> &p_font, int p_size) { void RichTextLabel::push_normal() { ERR_FAIL_COND(theme_cache.normal_font.is_null()); - push_font(theme_cache.normal_font, theme_cache.normal_font_size); + _push_def_font(NORMAL_FONT); } void RichTextLabel::push_bold() { ERR_FAIL_COND(theme_cache.bold_font.is_null()); - push_font(theme_cache.bold_font, theme_cache.bold_font_size); + _push_def_font(BOLD_FONT); } void RichTextLabel::push_bold_italics() { ERR_FAIL_COND(theme_cache.bold_italics_font.is_null()); - push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size); + _push_def_font(BOLD_ITALICS_FONT); } void RichTextLabel::push_italics() { ERR_FAIL_COND(theme_cache.italics_font.is_null()); - push_font(theme_cache.italics_font, theme_cache.italics_font_size); + _push_def_font(ITALICS_FONT); } void RichTextLabel::push_mono() { ERR_FAIL_COND(theme_cache.mono_font.is_null()); - push_font(theme_cache.mono_font, theme_cache.mono_font_size); + _push_def_font(MONO_FONT); } void RichTextLabel::push_font_size(int p_font_size) { @@ -3201,33 +3242,36 @@ void RichTextLabel::push_fade(int p_start_index, int p_length) { _add_item(item, true); } -void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f) { +void RichTextLabel::push_shake(int p_strength = 10, float p_rate = 24.0f, bool p_connected = true) { _stop_thread(); MutexLock data_lock(data_mutex); ItemShake *item = memnew(ItemShake); item->strength = p_strength; item->rate = p_rate; + item->connected = p_connected; _add_item(item, true); } -void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0f) { +void RichTextLabel::push_wave(float p_frequency = 1.0f, float p_amplitude = 10.0f, bool p_connected = true) { _stop_thread(); MutexLock data_lock(data_mutex); ItemWave *item = memnew(ItemWave); item->frequency = p_frequency; item->amplitude = p_amplitude; + item->connected = p_connected; _add_item(item, true); } -void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0f) { +void RichTextLabel::push_tornado(float p_frequency = 1.0f, float p_radius = 10.0f, bool p_connected = true) { _stop_thread(); MutexLock data_lock(data_mutex); ItemTornado *item = memnew(ItemTornado); item->frequency = p_frequency; item->radius = p_radius; + item->connected = p_connected; _add_item(item, true); } @@ -3635,9 +3679,9 @@ void RichTextLabel::append_text(const String &p_bbcode) { //use bold font in_bold = true; if (in_italics) { - push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size); + _push_def_font(BOLD_ITALICS_FONT); } else { - push_font(theme_cache.bold_font, theme_cache.bold_font_size); + _push_def_font(BOLD_FONT); } pos = brk_end + 1; tag_stack.push_front(tag); @@ -3645,15 +3689,15 @@ void RichTextLabel::append_text(const String &p_bbcode) { //use italics font in_italics = true; if (in_bold) { - push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size); + _push_def_font(BOLD_ITALICS_FONT); } else { - push_font(theme_cache.italics_font, theme_cache.italics_font_size); + _push_def_font(ITALICS_FONT); } pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "code") { //use monospace font - push_font(theme_cache.mono_font, theme_cache.mono_font_size); + _push_def_font(MONO_FONT); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag.begins_with("table=")) { @@ -4230,7 +4274,13 @@ void RichTextLabel::append_text(const String &p_bbcode) { rate = rate_option->value.to_float(); } - push_shake(strength, rate); + bool connected = true; + OptionMap::Iterator connected_option = bbcode_options.find("connected"); + if (connected_option) { + connected = connected_option->value.to_int(); + } + + push_shake(strength, rate, connected); pos = brk_end + 1; tag_stack.push_front("shake"); set_process_internal(true); @@ -4247,7 +4297,13 @@ void RichTextLabel::append_text(const String &p_bbcode) { period = period_option->value.to_float(); } - push_wave(period, amplitude); + bool connected = true; + OptionMap::Iterator connected_option = bbcode_options.find("connected"); + if (connected_option) { + connected = connected_option->value.to_int(); + } + + push_wave(period, amplitude, connected); pos = brk_end + 1; tag_stack.push_front("wave"); set_process_internal(true); @@ -4264,7 +4320,13 @@ void RichTextLabel::append_text(const String &p_bbcode) { frequency = frequency_option->value.to_float(); } - push_tornado(frequency, radius); + bool connected = true; + OptionMap::Iterator connected_option = bbcode_options.find("connected"); + if (connected_option) { + connected = connected_option->value.to_int(); + } + + push_tornado(frequency, radius, connected); pos = brk_end + 1; tag_stack.push_front("tornado"); set_process_internal(true); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 8bc28a9ecf..e714cb4ced 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -82,6 +82,15 @@ public: MENU_SELECT_ALL, }; + enum DefaultFont { + NORMAL_FONT, + BOLD_FONT, + ITALICS_FONT, + BOLD_ITALICS_FONT, + MONO_FONT, + CUSTOM_FONT, + }; + protected: virtual void _update_theme_item_cache() override; void _notification(int p_what); @@ -178,6 +187,7 @@ private: }; struct ItemFont : public Item { + DefaultFont def_font = CUSTOM_FONT; Ref<Font> font; int font_size = 0; ItemFont() { type = ITEM_FONT; } @@ -272,6 +282,7 @@ private: struct ItemFX : public Item { double elapsed_time = 0.f; + bool connected = true; }; struct ItemShake : public ItemFX { @@ -560,6 +571,7 @@ public: void add_newline(); bool remove_line(const int p_line); void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); + void _push_def_font(DefaultFont p_font); void push_font(const Ref<Font> &p_font, int p_size = 0); void push_font_size(int p_font_size); void push_outline_size(int p_font_size); @@ -579,9 +591,9 @@ public: void push_hint(const String &p_string); void push_table(int p_columns, InlineAlignment p_alignment = INLINE_ALIGNMENT_TOP); void push_fade(int p_start_index, int p_length); - void push_shake(int p_strength, float p_rate); - void push_wave(float p_frequency, float p_amplitude); - void push_tornado(float p_frequency, float p_radius); + void push_shake(int p_strength, float p_rate, bool p_connected); + void push_wave(float p_frequency, float p_amplitude, bool p_connected); + void push_tornado(float p_frequency, float p_radius, bool p_connected); void push_rainbow(float p_saturation, float p_value, float p_frequency); void push_bgcolor(const Color &p_color); void push_fgcolor(const Color &p_color); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index c12ac115b7..761072c5bc 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -501,8 +501,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) { follow_focus = p_follow; } -TypedArray<String> ScrollContainer::get_configuration_warnings() const { - TypedArray<String> warnings = Container::get_configuration_warnings(); +PackedStringArray ScrollContainer::get_configuration_warnings() const { + PackedStringArray warnings = Container::get_configuration_warnings(); int found = 0; diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index f4899846f4..0079358ef7 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -114,7 +114,7 @@ public: VScrollBar *get_v_scroll_bar(); void ensure_control_visible(Control *p_control); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; ScrollContainer(); }; diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 88e68ec763..3ad84cbc6d 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -227,8 +227,8 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) { } } -TypedArray<String> SubViewportContainer::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray SubViewportContainer::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); bool has_viewport = false; for (int i = 0; i < get_child_count(); i++) { diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 5b488fb79e..63a58b5f07 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -58,7 +58,7 @@ public: virtual Vector<int> get_allowed_size_flags_horizontal() const override; virtual Vector<int> get_allowed_size_flags_vertical() const override; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; SubViewportContainer(); }; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index f45d132a66..ab4808d312 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -519,12 +519,12 @@ void TabContainer::_refresh_tab_names() { } void TabContainer::add_child_notify(Node *p_child) { + Container::add_child_notify(p_child); + if (p_child == tab_bar) { return; } - Container::add_child_notify(p_child); - Control *c = Object::cast_to<Control>(p_child); if (!c || c->is_set_as_top_level()) { return; @@ -838,7 +838,7 @@ Size2 TabContainer::get_minimum_size() const { } Vector<Control *> controls = _get_tab_controls(); - int max_control_height = 0; + Size2 largest_child_min_size; for (int i = 0; i < controls.size(); i++) { Control *c = controls[i]; @@ -847,13 +847,14 @@ Size2 TabContainer::get_minimum_size() const { } Size2 cms = c->get_combined_minimum_size(); - ms.x = MAX(ms.x, cms.x); - max_control_height = MAX(max_control_height, cms.y); + largest_child_min_size.x = MAX(largest_child_min_size.x, cms.x); + largest_child_min_size.y = MAX(largest_child_min_size.y, cms.y); } - ms.y += max_control_height; + ms.y += largest_child_min_size.y; Size2 panel_ms = theme_cache.panel_style->get_minimum_size(); - ms.x = MAX(ms.x, panel_ms.x); + + ms.x = MAX(ms.x, largest_child_min_size.x + panel_ms.x); ms.y += panel_ms.y; return ms; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index bec378dd91..2c395ec07d 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -32,9 +32,6 @@ #include "core/io/compression.h" #include "scene/main/timer.h" -void HTTPRequest::_redirect_request(const String &p_new_url) { -} - Error HTTPRequest::_request() { return client->connect_to_host(url, port, use_tls, validate_tls); } @@ -48,6 +45,7 @@ Error HTTPRequest::_parse_url(const String &p_url) { body_len = -1; body.clear(); downloaded.set(0); + final_body_size.set(0); redirections = 0; String scheme; @@ -153,7 +151,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust client->set_blocking_mode(false); err = _request(); if (err != OK) { - call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return ERR_CANT_CONNECT; } @@ -169,7 +167,7 @@ void HTTPRequest::_thread_func(void *p_userdata) { Error err = hr->_request(); if (err != OK) { - hr->call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + hr->_defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); } else { while (!hr->thread_request_quit.is_set()) { bool exit = hr->_update_connection(); @@ -198,6 +196,7 @@ void HTTPRequest::cancel_request() { } file.unref(); + decompressor.unref(); client->close(); body.clear(); got_response = false; @@ -208,7 +207,7 @@ void HTTPRequest::cancel_request() { bool HTTPRequest::_handle_response(bool *ret_value) { if (!client->has_response()) { - call_deferred(SNAME("_request_done"), RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray()); *ret_value = true; return true; } @@ -219,6 +218,9 @@ bool HTTPRequest::_handle_response(bool *ret_value) { client->get_response_headers(&rheaders); response_headers.clear(); downloaded.set(0); + final_body_size.set(0); + decompressor.unref(); + for (const String &E : rheaders) { response_headers.push_back(E); } @@ -227,7 +229,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { // Handle redirect. if (max_redirects >= 0 && redirections >= max_redirects) { - call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray()); *ret_value = true; return true; } @@ -259,6 +261,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { body_len = -1; body.clear(); downloaded.set(0); + final_body_size.set(0); redirections = new_redirs; *ret_value = false; return true; @@ -266,13 +269,26 @@ bool HTTPRequest::_handle_response(bool *ret_value) { } } + // Check if we need to start streaming decompression. + String content_encoding; + if (accept_gzip) { + content_encoding = get_header_value(response_headers, "Content-Encoding").to_lower(); + } + if (content_encoding == "gzip") { + decompressor.instantiate(); + decompressor->start_decompression(false, get_download_chunk_size() * 2); + } else if (content_encoding == "deflate") { + decompressor.instantiate(); + decompressor->start_decompression(true, get_download_chunk_size() * 2); + } + return false; } bool HTTPRequest::_update_connection() { switch (client->get_status()) { case HTTPClient::STATUS_DISCONNECTED: { - call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return true; // End it, since it's disconnected. } break; case HTTPClient::STATUS_RESOLVING: { @@ -281,7 +297,7 @@ bool HTTPRequest::_update_connection() { return false; } break; case HTTPClient::STATUS_CANT_RESOLVE: { - call_deferred(SNAME("_request_done"), RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray()); return true; } break; @@ -291,7 +307,7 @@ bool HTTPRequest::_update_connection() { return false; } break; // Connecting to IP. case HTTPClient::STATUS_CANT_CONNECT: { - call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return true; } break; @@ -306,16 +322,16 @@ bool HTTPRequest::_update_connection() { return ret_value; } - call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); return true; } if (body_len < 0) { // Chunked transfer is done. - call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); + _defer_done(RESULT_SUCCESS, response_code, response_headers, body); return true; } - call_deferred(SNAME("_request_done"), RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray()); return true; // Request might have been done. } else { @@ -324,7 +340,7 @@ bool HTTPRequest::_update_connection() { int size = request_data.size(); Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size); if (err != OK) { - call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } @@ -347,7 +363,7 @@ bool HTTPRequest::_update_connection() { } if (!client->is_response_chunked() && client->get_response_body_length() == 0) { - call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); return true; } @@ -356,14 +372,14 @@ bool HTTPRequest::_update_connection() { body_len = client->get_response_body_length(); if (body_size_limit >= 0 && body_len > body_size_limit) { - call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); return true; } if (!download_to_file.is_empty()) { file = FileAccess::open(download_to_file, FileAccess::WRITE); if (file.is_null()) { - call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray()); return true; } } @@ -375,14 +391,33 @@ bool HTTPRequest::_update_connection() { } PackedByteArray chunk = client->read_response_body_chunk(); + downloaded.add(chunk.size()); + + // Decompress chunk if needed. + if (decompressor.is_valid()) { + Error err = decompressor->put_data(chunk.ptr(), chunk.size()); + if (err == OK) { + chunk.resize(decompressor->get_available_bytes()); + err = decompressor->get_data(chunk.ptrw(), chunk.size()); + } + if (err != OK) { + _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray()); + return true; + } + } + final_body_size.add(chunk.size()); + + if (body_size_limit >= 0 && final_body_size.get() > body_size_limit) { + _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); + return true; + } if (chunk.size()) { - downloaded.add(chunk.size()); if (file.is_valid()) { const uint8_t *r = chunk.ptr(); file->store_buffer(r, chunk.size()); if (file->get_error() != OK) { - call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray()); + _defer_done(RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray()); return true; } } else { @@ -390,19 +425,14 @@ bool HTTPRequest::_update_connection() { } } - if (body_size_limit >= 0 && downloaded.get() > body_size_limit) { - call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); - return true; - } - if (body_len >= 0) { if (downloaded.get() == body_len) { - call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); + _defer_done(RESULT_SUCCESS, response_code, response_headers, body); return true; } } else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) { // We read till EOF, with no errors. Request is done. - call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); + _defer_done(RESULT_SUCCESS, response_code, response_headers, body); return true; } @@ -410,11 +440,11 @@ bool HTTPRequest::_update_connection() { } break; // Request resulted in body: break which must be read. case HTTPClient::STATUS_CONNECTION_ERROR: { - call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } break; case HTTPClient::STATUS_TLS_HANDSHAKE_ERROR: { - call_deferred(SNAME("_request_done"), RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } break; } @@ -422,41 +452,13 @@ bool HTTPRequest::_update_connection() { ERR_FAIL_V(false); } +void HTTPRequest::_defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) { + call_deferred(SNAME("_request_done"), p_status, p_code, p_headers, p_data); +} + void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) { cancel_request(); - // Determine if the request body is compressed. - bool is_compressed; - String content_encoding = get_header_value(p_headers, "Content-Encoding").to_lower(); - Compression::Mode mode; - if (content_encoding == "gzip") { - mode = Compression::Mode::MODE_GZIP; - is_compressed = true; - } else if (content_encoding == "deflate") { - mode = Compression::Mode::MODE_DEFLATE; - is_compressed = true; - } else { - is_compressed = false; - } - - if (accept_gzip && is_compressed && p_data.size() > 0) { - // Decompress request body - PackedByteArray decompressed; - int result = Compression::decompress_dynamic(&decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode); - if (result == OK) { - emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, decompressed); - return; - } else if (result == -5) { - WARN_PRINT("Decompressed size of HTTP response body exceeded body_size_limit"); - p_status = RESULT_BODY_SIZE_LIMIT_EXCEEDED; - // Just return the raw data if we failed to decompress it. - } else { - WARN_PRINT("Failed to decompress HTTP response body"); - p_status = RESULT_BODY_DECOMPRESS_FAILED; - // Just return the raw data if we failed to decompress it. - } - } - emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, p_data); } @@ -566,7 +568,7 @@ double HTTPRequest::get_timeout() { void HTTPRequest::_timeout() { cancel_request(); - call_deferred(SNAME("_request_done"), RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray()); + _defer_done(RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray()); } void HTTPRequest::_bind_methods() { @@ -594,7 +596,6 @@ void HTTPRequest::_bind_methods() { ClassDB::bind_method(D_METHOD("get_downloaded_bytes"), &HTTPRequest::get_downloaded_bytes); ClassDB::bind_method(D_METHOD("get_body_size"), &HTTPRequest::get_body_size); - ClassDB::bind_method(D_METHOD("_redirect_request"), &HTTPRequest::_redirect_request); ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done); ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &HTTPRequest::set_timeout); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 290bacd9d2..80445684b0 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -32,6 +32,7 @@ #define HTTP_REQUEST_H #include "core/io/http_client.h" +#include "core/io/stream_peer_gzip.h" #include "core/os/thread.h" #include "core/templates/safe_refcount.h" #include "scene/main/node.h" @@ -84,10 +85,12 @@ private: String download_to_file; + Ref<StreamPeerGZIP> decompressor; Ref<FileAccess> file; int body_len = -1; SafeNumeric<int> downloaded; + SafeNumeric<int> final_body_size; int body_size_limit = -1; int redirections = 0; @@ -113,6 +116,7 @@ private: Thread thread; + void _defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data); void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data); static void _thread_func(void *p_userdata); diff --git a/scene/main/missing_node.cpp b/scene/main/missing_node.cpp index 395fdad9e4..7ce527fd9c 100644 --- a/scene/main/missing_node.cpp +++ b/scene/main/missing_node.cpp @@ -74,9 +74,9 @@ bool MissingNode::is_recording_properties() const { return recording_properties; } -TypedArray<String> MissingNode::get_configuration_warnings() const { +PackedStringArray MissingNode::get_configuration_warnings() const { // The mere existence of this node is warning. - TypedArray<String> ret; + PackedStringArray ret; ret.push_back(vformat(RTR("This node was saved as class type '%s', which was no longer available when this scene was loaded."), original_class)); ret.push_back(RTR("Data from the original node is kept as a placeholder until this type of node is available again. It can hence be safely re-saved without risk of data loss.")); return ret; diff --git a/scene/main/missing_node.h b/scene/main/missing_node.h index d200fbb47f..0003f71f29 100644 --- a/scene/main/missing_node.h +++ b/scene/main/missing_node.h @@ -55,7 +55,7 @@ public: void set_recording_properties(bool p_enable); bool is_recording_properties() const; - virtual TypedArray<String> get_configuration_warnings() const override; + virtual PackedStringArray get_configuration_warnings() const override; MissingNode(); }; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 29f4d4fb1c..a2b0f1a825 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2640,21 +2640,19 @@ void Node::clear_internal_tree_resource_paths() { } } -TypedArray<String> Node::get_configuration_warnings() const { - TypedArray<String> ret; +PackedStringArray Node::get_configuration_warnings() const { + PackedStringArray ret; Vector<String> warnings; if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) { - for (int i = 0; i < warnings.size(); i++) { - ret.push_back(warnings[i]); - } + ret.append_array(warnings); } return ret; } String Node::get_configuration_warnings_as_string() const { - TypedArray<String> warnings = get_configuration_warnings(); + PackedStringArray warnings = get_configuration_warnings(); String all_warnings = String(); for (int i = 0; i < warnings.size(); i++) { if (i > 0) { @@ -2662,7 +2660,7 @@ String Node::get_configuration_warnings_as_string() const { } // Format as a bullet point list to make multiple warnings easier to distinguish // from each other. - all_warnings += String::utf8("• ") + String(warnings[i]); + all_warnings += String::utf8("• ") + warnings[i]; } return all_warnings; } diff --git a/scene/main/node.h b/scene/main/node.h index 13a938ef97..4e6530cccd 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -477,7 +477,7 @@ public: _FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; } - virtual TypedArray<String> get_configuration_warnings() const; + virtual PackedStringArray get_configuration_warnings() const; String get_configuration_warnings_as_string() const; void update_configuration_warnings(); diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index 13034c5447..455b8c6866 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -271,8 +271,8 @@ void ShaderGlobalsOverride::_notification(int p_what) { } } -TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray ShaderGlobalsOverride::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (!active) { warnings.push_back(RTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.")); diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h index af99bf9aa7..f3d0074f28 100644 --- a/scene/main/shader_globals_override.h +++ b/scene/main/shader_globals_override.h @@ -58,7 +58,7 @@ protected: static void _bind_methods(); public: - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; ShaderGlobalsOverride(); }; diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index bb9359ef59..210b60171a 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -180,8 +180,8 @@ void Timer::_set_process(bool p_process, bool p_force) { processing = p_process; } -TypedArray<String> Timer::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray Timer::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (wait_time < 0.05 - CMP_EPSILON) { warnings.push_back(RTR("Very low timer wait times (< 0.05 seconds) may behave in significantly different ways depending on the rendered or physics frame rate.\nConsider using a script's process loop instead of relying on a Timer for very low wait times.")); diff --git a/scene/main/timer.h b/scene/main/timer.h index 8785d31a8a..53503e31b2 100644 --- a/scene/main/timer.h +++ b/scene/main/timer.h @@ -73,7 +73,7 @@ public: double get_time_left() const; - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_timer_process_callback(TimerProcessCallback p_callback); TimerProcessCallback get_timer_process_callback() const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 5295de5c09..a1c7139b25 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -795,11 +795,20 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, stretch_transform = p_stretch_transform; to_screen_rect = p_to_screen_rect; - if (p_allocated) { - RS::get_singleton()->viewport_set_size(viewport, size.width, size.height); - } else { - RS::get_singleton()->viewport_set_size(viewport, 0, 0); - } +#ifndef _3D_DISABLED + if (!use_xr) { +#endif + + if (p_allocated) { + RS::get_singleton()->viewport_set_size(viewport, size.width, size.height); + } else { + RS::get_singleton()->viewport_set_size(viewport, 0, 0); + } + +#ifndef _3D_DISABLED + } // if (!use_xr) +#endif + _update_global_transform(); update_configuration_warnings(); @@ -813,6 +822,19 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, } Size2i Viewport::_get_size() const { +#ifndef _3D_DISABLED + if (use_xr) { + if (XRServer::get_singleton() != nullptr) { + Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface(); + if (xr_interface.is_valid() && xr_interface->is_initialized()) { + Size2 xr_size = xr_interface->get_render_target_size(); + return (Size2i)xr_size; + } + } + return Size2i(); + } +#endif // _3D_DISABLED + return size; } @@ -2850,8 +2872,8 @@ Variant Viewport::gui_get_drag_data() const { return gui.drag_data; } -TypedArray<String> Viewport::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); +PackedStringArray Viewport::get_configuration_warnings() const { + PackedStringArray warnings = Node::get_configuration_warnings(); if (size.x <= 1 || size.y <= 1) { warnings.push_back(RTR("The Viewport size must be greater than or equal to 2 pixels on both dimensions to render anything.")); @@ -3612,9 +3634,20 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) { } void Viewport::set_use_xr(bool p_use_xr) { - use_xr = p_use_xr; + if (use_xr != p_use_xr) { + use_xr = p_use_xr; - RS::get_singleton()->viewport_set_use_xr(viewport, use_xr); + RS::get_singleton()->viewport_set_use_xr(viewport, use_xr); + + if (!use_xr) { + // Set viewport to previous size when exiting XR. + if (size_allocated) { + RS::get_singleton()->viewport_set_size(viewport, size.width, size.height); + } else { + RS::get_singleton()->viewport_set_size(viewport, 0, 0); + } + } + } } bool Viewport::is_using_xr() { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index afea3ea56c..471dc41246 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -568,7 +568,7 @@ public: bool is_input_disabled() const; Vector2 get_mouse_position() const; - virtual void warp_mouse(const Vector2 &p_position); + void warp_mouse(const Vector2 &p_position); void set_physics_object_picking(bool p_enable); bool get_physics_object_picking(); @@ -581,7 +581,7 @@ public: void gui_release_focus(); Control *gui_get_focus_owner(); - TypedArray<String> get_configuration_warnings() const override; + PackedStringArray get_configuration_warnings() const override; void set_debug_draw(DebugDraw p_debug_draw); DebugDraw get_debug_draw() const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 04f56bb874..ebe9587b31 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -986,18 +986,6 @@ DisplayServer::WindowID Window::get_window_id() const { return window_id; } -void Window::warp_mouse(const Vector2 &p_position) { - Transform2D xform = get_screen_transform(); - Vector2 gpos = xform.xform(p_position); - - if (transient_parent && !transient_parent->is_embedding_subwindows()) { - Transform2D window_trans = Transform2D().translated(get_position() + (transient_parent->get_visible_rect().size - transient_parent->get_real_size())); - gpos = window_trans.xform(gpos); - } - - Input::get_singleton()->warp_mouse(gpos); -} - void Window::set_wrap_controls(bool p_enable) { wrap_controls = p_enable; if (wrap_controls) { @@ -1153,7 +1141,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio Rect2 parent_rect; if (is_embedded()) { - parent_rect = get_parent_viewport()->get_visible_rect(); + parent_rect = _get_embedder()->get_visible_rect(); } else { DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); @@ -1179,7 +1167,7 @@ void Window::popup_centered(const Size2i &p_minsize) { Rect2 parent_rect; if (is_embedded()) { - parent_rect = get_parent_viewport()->get_visible_rect(); + parent_rect = _get_embedder()->get_visible_rect(); } else { DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); @@ -1207,7 +1195,7 @@ void Window::popup_centered_ratio(float p_ratio) { Rect2 parent_rect; if (is_embedded()) { - parent_rect = get_parent_viewport()->get_visible_rect(); + parent_rect = _get_embedder()->get_visible_rect(); } else { DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); diff --git a/scene/main/window.h b/scene/main/window.h index 8113117103..8c6ca65436 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -254,8 +254,6 @@ public: void set_use_font_oversampling(bool p_oversampling); bool is_using_font_oversampling() const; - void warp_mouse(const Vector2 &p_position) override; - void set_wrap_controls(bool p_enable); bool is_wrapping_controls() const; void child_controls_changed(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 72c57f1bfc..e536aeee51 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -794,6 +794,7 @@ void register_scene_types() { GDREGISTER_CLASS(CylinderMesh); GDREGISTER_CLASS(PlaneMesh); GDREGISTER_CLASS(PrismMesh); + GDREGISTER_CLASS(QuadMesh); GDREGISTER_CLASS(SphereMesh); GDREGISTER_CLASS(TextMesh); GDREGISTER_CLASS(TorusMesh); @@ -959,7 +960,6 @@ void register_scene_types() { ClassDB::add_compatibility_class("Navigation3D", "Node3D"); ClassDB::add_compatibility_class("Navigation2D", "Node2D"); ClassDB::add_compatibility_class("OpenSimplexNoise", "FastNoiseLite"); - ClassDB::add_compatibility_class("QuadMesh", "PlaneMesh"); ClassDB::add_compatibility_class("ToolButton", "Button"); ClassDB::add_compatibility_class("YSort", "Node2D"); // Portal and room occlusion was replaced by raster occlusion (OccluderInstance3D node). diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 9d5bc18c96..a52bfe97e7 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2317,9 +2317,7 @@ Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b, } Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const { - Variant dst; - Variant::interpolate(p_a, p_b, p_c, dst); - return dst; + return interpolate_variant(p_a, p_b, p_c); } real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const { @@ -5563,6 +5561,466 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in return false; } +// Helper math functions for Variant. +Variant Animation::add_variant(const Variant &a, const Variant &b) { + if (a.get_type() != b.get_type()) { + return a; + } + + switch (a.get_type()) { + case Variant::NIL: { + return Variant(); + } + case Variant::BOOL: { + return (a.operator real_t()) + (b.operator real_t()); // It is cast for interpolation. + } + case Variant::RECT2: { + const Rect2 ra = a.operator Rect2(); + const Rect2 rb = b.operator Rect2(); + return Rect2(ra.position + rb.position, ra.size + rb.size); + } + case Variant::RECT2I: { + const Rect2i ra = a.operator Rect2i(); + const Rect2i rb = b.operator Rect2i(); + return Rect2i(ra.position + rb.position, ra.size + rb.size); + } + case Variant::PLANE: { + const Plane pa = a.operator Plane(); + const Plane pb = b.operator Plane(); + return Plane(pa.normal + pb.normal, pa.d + pb.d); + } + case Variant::AABB: { + const ::AABB aa = a.operator ::AABB(); + const ::AABB ab = b.operator ::AABB(); + return ::AABB(aa.position + ab.position, aa.size + ab.size); + } + case Variant::QUATERNION: { + return (a.operator Quaternion()) * (b.operator Quaternion()); + } + case Variant::TRANSFORM2D: { + return (a.operator Transform2D()) * (b.operator Transform2D()); + } + case Variant::TRANSFORM3D: { + return (a.operator Transform3D()) * (b.operator Transform3D()); + } + default: { + return Variant::evaluate(Variant::OP_ADD, a, b); + } + } +} + +Variant Animation::subtract_variant(const Variant &a, const Variant &b) { + if (a.get_type() != b.get_type()) { + return a; + } + + switch (a.get_type()) { + case Variant::NIL: { + return Variant(); + } + case Variant::BOOL: { + return (a.operator real_t()) - (b.operator real_t()); // It is cast for interpolation. + } + case Variant::RECT2: { + const Rect2 ra = a.operator Rect2(); + const Rect2 rb = b.operator Rect2(); + return Rect2(ra.position - rb.position, ra.size - rb.size); + } + case Variant::RECT2I: { + const Rect2i ra = a.operator Rect2i(); + const Rect2i rb = b.operator Rect2i(); + return Rect2i(ra.position - rb.position, ra.size - rb.size); + } + case Variant::PLANE: { + const Plane pa = a.operator Plane(); + const Plane pb = b.operator Plane(); + return Plane(pa.normal - pb.normal, pa.d - pb.d); + } + case Variant::AABB: { + const ::AABB aa = a.operator ::AABB(); + const ::AABB ab = b.operator ::AABB(); + return ::AABB(aa.position - ab.position, aa.size - ab.size); + } + case Variant::QUATERNION: { + return (b.operator Quaternion()).inverse() * (a.operator Quaternion()); + } + case Variant::TRANSFORM2D: { + return (b.operator Transform2D()).inverse() * (a.operator Transform2D()); + } + case Variant::TRANSFORM3D: { + return (b.operator Transform3D()).inverse() * (a.operator Transform3D()); + } + default: { + return Variant::evaluate(Variant::OP_SUBTRACT, a, b); + } + } +} + +Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + real_t va = a; + real_t vb = b; + return va + vb * c; + } + return a; + } + + switch (a.get_type()) { + case Variant::NIL: { + return Variant(); + } + case Variant::INT: { + return int((a.operator int64_t()) + (b.operator int64_t()) * c + 0.5); + } + case Variant::FLOAT: { + return (a.operator double()) + (b.operator double()) * c; + } + case Variant::VECTOR2: { + return (a.operator Vector2()) + (b.operator Vector2()) * c; + } + case Variant::VECTOR2I: { + const Vector2i va = a.operator Vector2i(); + const Vector2i vb = b.operator Vector2i(); + return Vector2i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5)); + } + case Variant::RECT2: { + const Rect2 ra = a.operator Rect2(); + const Rect2 rb = b.operator Rect2(); + return Rect2(ra.position + rb.position * c, ra.size + rb.size * c); + } + case Variant::RECT2I: { + const Rect2i ra = a.operator Rect2i(); + const Rect2i rb = b.operator Rect2i(); + return Rect2i(int32_t(ra.position.x + rb.position.x * c + 0.5), int32_t(ra.position.y + rb.position.y * c + 0.5), int32_t(ra.size.x + rb.size.x * c + 0.5), int32_t(ra.size.y + rb.size.y * c + 0.5)); + } + case Variant::VECTOR3: { + return (a.operator Vector3()) + (b.operator Vector3()) * c; + } + case Variant::VECTOR3I: { + const Vector3i va = a.operator Vector3i(); + const Vector3i vb = b.operator Vector3i(); + return Vector3i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5)); + } + case Variant::VECTOR4: { + return (a.operator Vector4()) + (b.operator Vector4()) * c; + } + case Variant::VECTOR4I: { + const Vector4i va = a.operator Vector4i(); + const Vector4i vb = b.operator Vector4i(); + return Vector4i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5), int32_t(va.w + vb.w * c + 0.5)); + } + case Variant::PLANE: { + const Plane pa = a.operator Plane(); + const Plane pb = b.operator Plane(); + return Plane(pa.normal + pb.normal * c, pa.d + pb.d * c); + } + case Variant::COLOR: { + return (a.operator Color()) + (b.operator Color()) * c; + } + case Variant::AABB: { + const ::AABB aa = a.operator ::AABB(); + const ::AABB ab = b.operator ::AABB(); + return ::AABB(aa.position + ab.position * c, aa.size + ab.size * c); + } + case Variant::BASIS: { + return (a.operator Basis()) + (b.operator Basis()) * c; + } + case Variant::QUATERNION: { + return (a.operator Quaternion()) * Quaternion().slerp((b.operator Quaternion()), c); + } + case Variant::TRANSFORM2D: { + return (a.operator Transform2D()) * Transform2D().interpolate_with((b.operator Transform2D()), c); + } + case Variant::TRANSFORM3D: { + return (a.operator Transform3D()) * Transform3D().interpolate_with((b.operator Transform3D()), c); + } + default: { + return c < 0.5 ? a : b; + } + } +} + +Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c) { + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + real_t va = a; + real_t vb = b; + return va + (vb - va) * c; + } + return a; + } + + switch (a.get_type()) { + case Variant::NIL: { + return Variant(); + } + case Variant::INT: { + const int64_t va = a.operator int64_t(); + return int(va + ((b.operator int64_t()) - va) * c); + } + case Variant::FLOAT: { + const real_t va = a.operator real_t(); + return va + ((b.operator real_t()) - va) * c; + } + case Variant::VECTOR2: { + return (a.operator Vector2()).lerp(b.operator Vector2(), c); + } + case Variant::VECTOR2I: { + const Vector2i va = a.operator Vector2i(); + const Vector2i vb = b.operator Vector2i(); + return Vector2i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c)); + } + case Variant::RECT2: { + const Rect2 ra = a.operator Rect2(); + const Rect2 rb = b.operator Rect2(); + return Rect2(ra.position.lerp(rb.position, c), ra.size.lerp(rb.size, c)); + } + case Variant::RECT2I: { + const Rect2i ra = a.operator Rect2i(); + const Rect2i rb = b.operator Rect2i(); + return Rect2i(int32_t(ra.position.x + (rb.position.x - ra.position.x) * c), int32_t(ra.position.y + (rb.position.y - ra.position.y) * c), int32_t(ra.size.x + (rb.size.x - ra.size.x) * c), int32_t(ra.size.y + (rb.size.y - ra.size.y) * c)); + } + case Variant::VECTOR3: { + return (a.operator Vector3()).lerp(b.operator Vector3(), c); + } + case Variant::VECTOR3I: { + const Vector3i va = a.operator Vector3i(); + const Vector3i vb = b.operator Vector3i(); + return Vector3i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c)); + } + case Variant::VECTOR4: { + return (a.operator Vector4()).lerp(b.operator Vector4(), c); + } + case Variant::VECTOR4I: { + const Vector4i va = a.operator Vector4i(); + const Vector4i vb = b.operator Vector4i(); + return Vector4i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c), int32_t(va.w + (vb.w - va.w) * c)); + } + case Variant::PLANE: { + const Plane pa = a.operator Plane(); + const Plane pb = b.operator Plane(); + return Plane(pa.normal.lerp(pb.normal, c), pa.d + (pb.d - pa.d) * c); + } + case Variant::COLOR: { + return (a.operator Color()).lerp(b.operator Color(), c); + } + case Variant::AABB: { + const ::AABB aa = a.operator ::AABB(); + const ::AABB ab = b.operator ::AABB(); + return ::AABB(aa.position.lerp(ab.position, c), aa.size.lerp(ab.size, c)); + } + case Variant::BASIS: { + return (a.operator Basis()).lerp(b.operator Basis(), c); + } + case Variant::QUATERNION: { + return (a.operator Quaternion()).slerp(b.operator Quaternion(), c); + } + case Variant::TRANSFORM2D: { + return (a.operator Transform2D()).interpolate_with(b.operator Transform2D(), c); + } + case Variant::TRANSFORM3D: { + return (a.operator Transform3D()).interpolate_with(b.operator Transform3D(), c); + } + case Variant::STRING: { + // This is pretty funny and bizarre, but artists like to use it for typewriter effects. + const String sa = a.operator String(); + const String sb = b.operator String(); + String dst; + int sa_len = sa.length(); + int sb_len = sb.length(); + int csize = sa_len + (sb_len - sa_len) * c; + if (csize == 0) { + return ""; + } + dst.resize(csize + 1); + dst[csize] = 0; + int split = csize / 2; + + for (int i = 0; i < csize; i++) { + char32_t chr = ' '; + + if (i < split) { + if (i < sa.length()) { + chr = sa[i]; + } else if (i < sb.length()) { + chr = sb[i]; + } + + } else { + if (i < sb.length()) { + chr = sb[i]; + } else if (i < sa.length()) { + chr = sa[i]; + } + } + + dst[i] = chr; + } + + return dst; + } + case Variant::PACKED_INT32_ARRAY: { + const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a); + const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b); + int32_t sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<int32_t> v; + v.resize(sz); + { + int32_t *vw = v.ptrw(); + const int32_t *ar = arr_a->ptr(); + const int32_t *br = arr_b->ptr(); + + Variant va; + for (int32_t i = 0; i < sz; i++) { + va = interpolate_variant(ar[i], br[i], c); + vw[i] = va; + } + } + return v; + } + } + case Variant::PACKED_INT64_ARRAY: { + const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a); + const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b); + int64_t sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<int64_t> v; + v.resize(sz); + { + int64_t *vw = v.ptrw(); + const int64_t *ar = arr_a->ptr(); + const int64_t *br = arr_b->ptr(); + + Variant va; + for (int64_t i = 0; i < sz; i++) { + va = interpolate_variant(ar[i], br[i], c); + vw[i] = va; + } + } + return v; + } + } + case Variant::PACKED_FLOAT32_ARRAY: { + const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a); + const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<float> v; + v.resize(sz); + { + float *vw = v.ptrw(); + const float *ar = arr_a->ptr(); + const float *br = arr_b->ptr(); + + Variant va; + for (int i = 0; i < sz; i++) { + va = interpolate_variant(ar[i], br[i], c); + vw[i] = va; + } + } + return v; + } + } + case Variant::PACKED_FLOAT64_ARRAY: { + const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a); + const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<double> v; + v.resize(sz); + { + double *vw = v.ptrw(); + const double *ar = arr_a->ptr(); + const double *br = arr_b->ptr(); + + Variant va; + for (int i = 0; i < sz; i++) { + va = interpolate_variant(ar[i], br[i], c); + vw[i] = va; + } + } + return v; + } + } + case Variant::PACKED_VECTOR2_ARRAY: { + const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a); + const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<Vector2> v; + v.resize(sz); + { + Vector2 *vw = v.ptrw(); + const Vector2 *ar = arr_a->ptr(); + const Vector2 *br = arr_b->ptr(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].lerp(br[i], c); + } + } + return v; + } + } + case Variant::PACKED_VECTOR3_ARRAY: { + const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a); + const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<Vector3> v; + v.resize(sz); + { + Vector3 *vw = v.ptrw(); + const Vector3 *ar = arr_a->ptr(); + const Vector3 *br = arr_b->ptr(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].lerp(br[i], c); + } + } + return v; + } + } + case Variant::PACKED_COLOR_ARRAY: { + const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a); + const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + return a; + } else { + Vector<Color> v; + v.resize(sz); + { + Color *vw = v.ptrw(); + const Color *ar = arr_a->ptr(); + const Color *br = arr_b->ptr(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].lerp(br[i], c); + } + } + return v; + } + } + default: { + return c < 0.5 ? a : b; + } + } +} + Animation::Animation() {} Animation::~Animation() { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 46a88df130..49c8fa4c22 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -496,6 +496,12 @@ public: void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3); void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests + // Helper math functions for Variant. + static Variant add_variant(const Variant &a, const Variant &b); + static Variant subtract_variant(const Variant &a, const Variant &b); + static Variant blend_variant(const Variant &a, const Variant &b, float c); + static Variant interpolate_variant(const Variant &a, const Variant &b, float c); + Animation(); ~Animation(); }; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index e47bfef576..c1e30dd93c 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -257,23 +257,25 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { groups[last_group][last_subgroup].push_back(info); } - // Sort groups alphabetically. - List<UniformProp> props; + List<String> group_names; for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) { - for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) { - for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) { - if (subgroup->key == "<None>") { - props.push_back({ group->key, item->get() }); - } else { - props.push_back({ group->key + "::" + subgroup->key, item->get() }); - } - } - } + group_names.push_back(group->key); } - props.sort_custom<UniformPropComparator>(); + group_names.sort(); - for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) { - p_list->push_back(E->get().info); + for (const String &group_name : group_names) { + List<String> subgroup_names; + HashMap<String, List<PropertyInfo>> &subgroups = groups[group_name]; + for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = subgroups.begin(); subgroup; ++subgroup) { + subgroup_names.push_back(subgroup->key); + } + subgroup_names.sort(); + for (const String &subgroup_name : subgroup_names) { + List<PropertyInfo> &prop_infos = subgroups[subgroup_name]; + for (List<PropertyInfo>::Element *item = prop_infos.front(); item; item = item->next()) { + p_list->push_back(item->get()); + } + } } } } diff --git a/scene/resources/material.h b/scene/resources/material.h index 6c81293ee3..dd9589c577 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -84,17 +84,6 @@ class ShaderMaterial : public Material { HashMap<StringName, Variant> param_cache; - struct UniformProp { - String str; - PropertyInfo info; - }; - - struct UniformPropComparator { - bool operator()(const UniformProp &p_a, const UniformProp &p_b) const { - return p_a.str.naturalnocasecmp_to(p_b.str) < 0; - } - }; - protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 280477ebfa..65823a8f7f 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -262,6 +262,18 @@ public: VARIANT_ENUM_CAST(PlaneMesh::Orientation) +/* + A flat rectangle, inherits from PlaneMesh but defaults to facing the Z-plane. +*/ +class QuadMesh : public PlaneMesh { + GDCLASS(QuadMesh, PlaneMesh); + +public: + QuadMesh() { + set_orientation(FACE_Z); + } +}; + /** A prism shapen, handy for ramps, triangles, etc. */ diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp index 1367ea86dd..61a0350440 100644 --- a/scene/resources/skeleton_profile.cpp +++ b/scene/resources/skeleton_profile.cpp @@ -566,7 +566,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[14].bone_name = "LeftThumbMetacarpal"; bones.write[14].bone_parent = "LeftHand"; - bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0.707, 0.577, 0.408, -0.707, 0.577, 0.408, -0.025, 0, 0); + bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0, 0.816, 0.577, -1, 0, 0, -0.025, 0.025, 0); bones.write[14].handle_offset = Vector2(0.4, 0.8); bones.write[14].group = "LeftHand"; @@ -686,7 +686,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[33].bone_name = "RightThumbMetacarpal"; bones.write[33].bone_parent = "RightHand"; - bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, -0.707, 0.577, 0.408, 0.707, 0.577, 0.408, 0.025, 0, 0); + bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, 0, 0.816, 0.577, 1, 0, 0, 0.025, 0.025, 0); bones.write[33].handle_offset = Vector2(0.6, 0.8); bones.write[33].group = "RightHand"; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index dda8e29b6a..e1a1c71420 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -678,6 +678,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("window_set_flag", "flag", "enabled", "window_id"), &DisplayServer::window_set_flag, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_get_flag", "flag", "window_id"), &DisplayServer::window_get_flag, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_set_window_buttons_offset", "offset", "window_id"), &DisplayServer::window_set_window_buttons_offset, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_get_safe_title_margins", "window_id"), &DisplayServer::window_get_safe_title_margins, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID)); diff --git a/servers/display_server.h b/servers/display_server.h index ab4f9fc499..42c254cd2f 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -380,7 +380,8 @@ public: virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0; virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0; - virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); }; + virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {} + virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); } virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0; diff --git a/servers/physics_2d/godot_collision_solver_2d.cpp b/servers/physics_2d/godot_collision_solver_2d.cpp index 761a1c33e2..52237539c0 100644 --- a/servers/physics_2d/godot_collision_solver_2d.cpp +++ b/servers/physics_2d/godot_collision_solver_2d.cpp @@ -229,6 +229,7 @@ bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transfor if (type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { if (type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { + WARN_PRINT_ONCE("Collisions between world boundaries are not supported."); return false; } @@ -240,6 +241,7 @@ bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transfor } else if (type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY) { if (type_B == PhysicsServer2D::SHAPE_SEPARATION_RAY) { + WARN_PRINT_ONCE("Collisions between two rays are not supported."); return false; //no ray-ray } @@ -251,6 +253,7 @@ bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transfor } else if (concave_B) { if (concave_A) { + WARN_PRINT_ONCE("Collisions between two concave shapes are not supported."); return false; } diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp index 094d77a582..9fe0e3eb84 100644 --- a/servers/physics_3d/godot_collision_solver_3d.cpp +++ b/servers/physics_3d/godot_collision_solver_3d.cpp @@ -370,12 +370,15 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T if (type_A == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { if (type_B == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { + WARN_PRINT_ONCE("Collisions between world boundaries are not supported."); return false; } if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) { + WARN_PRINT_ONCE("Collisions between world boundaries and rays are not supported."); return false; } if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) { + WARN_PRINT_ONCE("Collisions between world boundaries and soft bodies are not supported."); return false; } @@ -387,6 +390,7 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T } else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) { if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) { + WARN_PRINT_ONCE("Collisions between rays are not supported."); return false; } @@ -398,7 +402,7 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T } else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) { if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) { - // Soft Body / Soft Body not supported. + WARN_PRINT_ONCE("Collisions between soft bodies are not supported."); return false; } @@ -410,6 +414,7 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T } else if (concave_B) { if (concave_A) { + WARN_PRINT_ONCE("Collisions between two concave shapes are not supported."); return false; } diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 6384b631b2..bd57a6a375 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -487,7 +487,7 @@ public: bool collide_separation_ray = false; HashSet<RID> exclude_bodies; HashSet<ObjectID> exclude_objects; - bool recovery_as_collision = false; + bool recovery_as_collision = false; // Don't report margin recovery as collision by default, only used for floor snapping. MotionParameters() {} diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 468b0aaecc..2151d84e40 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -524,7 +524,7 @@ public: bool collide_separation_ray = false; HashSet<RID> exclude_bodies; HashSet<ObjectID> exclude_objects; - bool recovery_as_collision = false; + bool recovery_as_collision = false; // Don't report margin recovery as collision by default, only used for floor snapping. MotionParameters() {} diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 4a2a947b94..e41373ed37 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -180,7 +180,7 @@ public: void voxel_gi_set_quality(RS::VoxelGIQuality) override {} - void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {} + void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_info = nullptr) override {} void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {} void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index aa9772a483..c5818d9290 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -189,7 +189,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * RenderingServerDefault::redraw_request(); } - if (ci->commands != nullptr) { + if (ci->commands != nullptr || ci->copy_back_buffer) { ci->final_transform = xform; ci->final_modulate = modulate * ci->self_modulate; ci->global_rect_cache = global_rect; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 78d4ded617..8e04191e35 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -34,7 +34,7 @@ #include "servers/rendering/environment/renderer_fog.h" #include "servers/rendering/environment/renderer_gi.h" #include "servers/rendering/renderer_canvas_render.h" -#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/rendering_method.h" #include "servers/rendering/storage/camera_attributes_storage.h" #include "servers/rendering/storage/light_storage.h" #include "servers/rendering/storage/material_storage.h" 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 33d7ddd6e8..63fd10886d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -477,7 +477,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p prev_material_uniform_set = material_uniform_set; } - if (surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH) { + if ((surf->owner->base_flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH) { mesh_storage->_multimesh_get_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset); } @@ -578,47 +578,21 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers; + RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID(); + RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID(); - //Projection projection = p_render_data->cam_projection; - //projection.flip_y(); // Vulkan and modern APIs use Y-Down - Projection correction; - correction.set_depth_correction(p_flip_y); - correction.add_jitter_offset(p_render_data->taa_jitter); - Projection projection = correction * p_render_data->cam_projection; - - //store camera into ubo - RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix); - RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix); - RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix); - - for (uint32_t v = 0; v < p_render_data->view_count; v++) { - projection = correction * p_render_data->view_projection[v]; - RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix_view[v]); - RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]); - - scene_state.ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x; - scene_state.ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y; - scene_state.ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z; - scene_state.ubo.eye_offset[v][3] = 0.0; + // May do this earlier in RenderSceneRenderRD::render_scene + if (p_index >= (int)scene_state.uniform_buffers.size()) { + uint32_t from = scene_state.uniform_buffers.size(); + scene_state.uniform_buffers.resize(p_index + 1); + for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { + scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer(); + } } - scene_state.ubo.taa_jitter[0] = p_render_data->taa_jitter.x; - scene_state.ubo.taa_jitter[1] = p_render_data->taa_jitter.y; - - scene_state.ubo.z_far = p_render_data->z_far; - scene_state.ubo.z_near = p_render_data->z_near; - - scene_state.ubo.pancake_shadows = p_pancake_shadows; - - RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); - RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); - RendererRD::MaterialStorage::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); - RendererRD::MaterialStorage::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers); - Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); - scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; - scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; + // now do implementation UBO scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_render_data->cluster_size); scene_state.ubo.max_cluster_element_count_div_32 = p_render_data->cluster_max_elements / 32; @@ -629,22 +603,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.cluster_width = cluster_screen_width; } - if (p_render_data->shadow_atlas.is_valid()) { - Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas); - scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; - scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; - } - { - Vector2 dss = directional_shadow_get_size(); - scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x; - scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y; - } - //time global variables - scene_state.ubo.time = time; - scene_state.ubo.gi_upscale_for_msaa = false; scene_state.ubo.volumetric_fog_enabled = false; - scene_state.ubo.fog_enabled = false; if (rd.is_valid()) { if (rd->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) { @@ -672,59 +632,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat } if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - scene_state.ubo.use_ambient_light = true; - scene_state.ubo.ambient_light_color_energy[0] = 1; - scene_state.ubo.ambient_light_color_energy[1] = 1; - scene_state.ubo.ambient_light_color_energy[2] = 1; - scene_state.ubo.ambient_light_color_energy[3] = 1.0; - scene_state.ubo.use_ambient_cubemap = false; - scene_state.ubo.use_reflection_cubemap = false; scene_state.ubo.ss_effects_flags = 0; - } else if (is_environment(p_render_data->environment)) { - RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment); - RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment); - - float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment); - - scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier; - - scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment); - - //ambient - if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { - Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment); - color = color.srgb_to_linear(); - - scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier; - scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier; - scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier; - scene_state.ubo.use_ambient_light = true; - scene_state.ubo.use_ambient_cubemap = false; - } else { - float energy = environment_get_ambient_light_energy(p_render_data->environment); - Color color = environment_get_ambient_light(p_render_data->environment); - color = color.srgb_to_linear(); - scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; - scene_state.ubo.ambient_light_color_energy[1] = color.g * energy; - scene_state.ubo.ambient_light_color_energy[2] = color.b * energy; - - Basis sky_transform = environment_get_sky_orientation(p_render_data->environment); - sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis; - RendererRD::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); - - scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; - scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; - } - - //specular - RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment); - if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { - scene_state.ubo.use_reflection_cubemap = true; - } else { - scene_state.ubo.use_reflection_cubemap = false; - } - scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_channel_affect(p_render_data->environment); scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment); uint32_t ss_flags = 0; @@ -733,97 +642,19 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat ss_flags |= environment_get_ssil_enabled(p_render_data->environment) ? 2 : 0; } scene_state.ubo.ss_effects_flags = ss_flags; - - scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment); - scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); - scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment); - scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment); - scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment); - - Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear(); - float fog_energy = environment_get_fog_light_energy(p_render_data->environment); - - scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; - scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; - scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; - - scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment); - } else { - if (p_render_data->reflection_probe.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { - scene_state.ubo.use_ambient_light = false; - } else { - scene_state.ubo.use_ambient_light = true; - Color clear_color = p_default_bg_color; - clear_color = clear_color.srgb_to_linear(); - scene_state.ubo.ambient_light_color_energy[0] = clear_color.r; - scene_state.ubo.ambient_light_color_energy[1] = clear_color.g; - scene_state.ubo.ambient_light_color_energy[2] = clear_color.b; - scene_state.ubo.ambient_light_color_energy[3] = 1.0; - } - - scene_state.ubo.use_ambient_cubemap = false; - scene_state.ubo.use_reflection_cubemap = false; scene_state.ubo.ss_effects_flags = 0; } - if (p_render_data->camera_attributes.is_valid()) { - scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); - scene_state.ubo.IBL_exposure_normalization = 1.0; - if (is_environment(p_render_data->environment)) { - RID sky_rid = environment_get_sky(p_render_data->environment); - if (sky_rid.is_valid()) { - float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier(); - scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid)); - } - } - } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) { - // This branch is triggered when using render_material(). - // Emissive is set outside the function, so don't set it. - // IBL isn't used don't set it. - } else { - scene_state.ubo.emissive_exposure_normalization = 1.0; - scene_state.ubo.IBL_exposure_normalization = 1.0; - } - - scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); - scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); - scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); - - if (rd.is_valid()) { - if (rd->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) { - memcpy(&scene_state.prev_ubo, &scene_state.ubo, sizeof(SceneState::UBO)); - - Projection prev_correction; - prev_correction.set_depth_correction(true); - prev_correction.add_jitter_offset(p_render_data->prev_taa_jitter); - Projection prev_projection = prev_correction * p_render_data->prev_cam_projection; - - //store camera into ubo - RendererRD::MaterialStorage::store_camera(prev_projection, scene_state.prev_ubo.projection_matrix); - RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), scene_state.prev_ubo.inv_projection_matrix); - RendererRD::MaterialStorage::store_transform(p_render_data->prev_cam_transform, scene_state.prev_ubo.inv_view_matrix); - RendererRD::MaterialStorage::store_transform(p_render_data->prev_cam_transform.affine_inverse(), scene_state.prev_ubo.view_matrix); - - for (uint32_t v = 0; v < p_render_data->view_count; v++) { - prev_projection = prev_correction * p_render_data->view_projection[v]; - RendererRD::MaterialStorage::store_camera(prev_projection, scene_state.prev_ubo.projection_matrix_view[v]); - RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), scene_state.prev_ubo.inv_projection_matrix_view[v]); - } - scene_state.prev_ubo.taa_jitter[0] = p_render_data->prev_taa_jitter.x; - scene_state.prev_ubo.taa_jitter[1] = p_render_data->prev_taa_jitter.y; - scene_state.prev_ubo.time -= time_step; + if (p_index >= (int)scene_state.implementation_uniform_buffers.size()) { + uint32_t from = scene_state.implementation_uniform_buffers.size(); + scene_state.implementation_uniform_buffers.resize(p_index + 1); + for (uint32_t i = from; i < scene_state.implementation_uniform_buffers.size(); i++) { + scene_state.implementation_uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); } } - if (p_index >= (int)scene_state.uniform_buffers.size()) { - uint32_t from = scene_state.uniform_buffers.size(); - scene_state.uniform_buffers.resize(p_index + 1); - for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { - scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO) * 2); - } - } - RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO) * 2, &scene_state.ubo_data, RD::BARRIER_MASK_RASTER); + RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); } void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) { @@ -939,9 +770,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } uint32_t lightmap_captures_used = 0; - Plane near_plane = Plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin); - near_plane.d += p_render_data->cam_projection.get_z_near(); - float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near(); + Plane near_plane = Plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); + near_plane.d += p_render_data->scene_data->cam_projection.get_z_near(); + float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near(); RenderList *rl = &render_list[p_render_list]; _update_dirty_geometry_instances(); @@ -972,7 +803,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con float fade_alpha = 1.0; if (inst->fade_near || inst->fade_far) { - float fade_dist = inst->transform.origin.distance_to(p_render_data->cam_transform.origin); + float fade_dist = inst->transform.origin.distance_to(p_render_data->scene_data->cam_transform.origin); // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. if (inst->fade_far && fade_dist > inst->fade_far_begin) { fade_alpha = Math::smoothstep(0.0f, 1.0f, 1.0f - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin)); @@ -1067,13 +898,13 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con // LOD - if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) { + if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) { //lod - Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal); - Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal); + Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->scene_data->lod_camera_plane.normal); + Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal); - float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min); - float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max); + float distance_min = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_min); + float distance_max = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_max); float distance = 0.0; @@ -1086,12 +917,12 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con distance = -distance_max; } - if (p_render_data->cam_orthogonal) { + if (p_render_data->scene_data->cam_orthogonal) { distance = 1.0; } uint32_t indices; - surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices); + surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices); if (p_render_data->render_info) { indices = _indices_to_primitives(surf->primitive, indices); if (p_render_list == RENDER_LIST_OPAQUE) { //opaque @@ -1153,8 +984,8 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con scene_state.used_depth_texture = true; } - if (p_color_pass_flags & COLOR_PASS_FLAG_MOTION_VECTORS && flags & INSTANCE_DATA_FLAG_MULTIMESH) { - if (RendererRD::MeshStorage::get_singleton()->_multimesh_enable_motion_vectors(inst->data->base)) { + if (p_color_pass_flags & COLOR_PASS_FLAG_MOTION_VECTORS) { + if ((flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH && RendererRD::MeshStorage::get_singleton()->_multimesh_enable_motion_vectors(inst->data->base)) { inst->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(inst->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); } } @@ -1230,9 +1061,18 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RENDER_TIMESTAMP("Setup 3D Scene"); - //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; - scene_state.ubo.directional_light_count = 0; - scene_state.ubo.opaque_prepass_threshold = 0.99f; + // check if we need motion vectors + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) { + p_render_data->scene_data->calculate_motion_vectors = true; + } else if (rb.is_valid() && rb->get_use_taa()) { + p_render_data->scene_data->calculate_motion_vectors = true; + } else { + p_render_data->scene_data->calculate_motion_vectors = false; + } + + //p_render_data->scene_data->subsurface_scatter_width = subsurface_scatter_size; + p_render_data->scene_data->directional_light_count = 0; + p_render_data->scene_data->opaque_prepass_threshold = 0.99f; Size2i screen_size; RID color_framebuffer; @@ -1295,7 +1135,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co }; } - if (p_render_data->view_count > 1) { + if (p_render_data->scene_data->view_count > 1) { color_pass_flags |= COLOR_PASS_FLAG_MULTIVIEW; } @@ -1319,14 +1159,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co ERR_FAIL(); //bug? } - scene_state.ubo.viewport_size[0] = screen_size.x; - scene_state.ubo.viewport_size[1] = screen_size.y; - - scene_state.ubo.emissive_exposure_normalization = -1.0; + p_render_data->scene_data->emissive_exposure_normalization = -1.0; RD::get_singleton()->draw_command_begin_label("Render Setup"); - _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform); + _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform); _setup_voxelgis(*p_render_data->voxel_gi_instances); _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); @@ -1406,20 +1243,20 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); RD::get_singleton()->draw_command_begin_label("Setup Sky"); - Projection projection = p_render_data->cam_projection; + Projection projection = p_render_data->scene_data->cam_projection; if (p_render_data->reflection_probe.is_valid()) { Projection correction; correction.set_depth_correction(true); - projection = correction * p_render_data->cam_projection; + projection = correction * p_render_data->scene_data->cam_projection; } - sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this); + sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this); sky_energy_multiplier *= bg_energy_multiplier; RID sky_rid = environment_get_sky(p_render_data->environment); if (sky_rid.is_valid()) { - sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier); + sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid); } else { // do not try to draw sky if invalid @@ -1458,7 +1295,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID()); bool finish_depth = using_ssao || using_sdfgi || using_voxelgi; - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count); _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear); RD::get_singleton()->draw_command_end_label(); @@ -1498,8 +1335,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); - scene_state.ubo.directional_light_count = p_render_data->directional_light_count; - scene_state.ubo.opaque_prepass_threshold = 0.0f; + p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count; + p_render_data->scene_data->opaque_prepass_threshold = 0.0f; _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, rb.is_valid()); @@ -1528,7 +1365,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count); _render_list_with_threads(&render_list_params, color_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); if (will_continue_color && using_separate_specular) { // close the specular framebuffer, as it's no longer used @@ -1546,7 +1383,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co Projection dc; dc.set_depth_correction(true); - Projection cm = (dc * p_render_data->cam_projection) * Projection(p_render_data->cam_transform.affine_inverse()); + Projection cm = (dc * p_render_data->scene_data->cam_projection) * Projection(p_render_data->scene_data->cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs"); for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) { @@ -1564,10 +1401,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co Projection dc; dc.set_depth_correction(true); Projection cms[RendererSceneRender::MAX_RENDER_VIEWS]; - for (uint32_t v = 0; v < p_render_data->view_count; v++) { - cms[v] = (dc * p_render_data->view_projection[v]) * Projection(p_render_data->cam_transform.affine_inverse()); + for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) { + cms[v] = (dc * p_render_data->scene_data->view_projection[v]) * Projection(p_render_data->scene_data->cam_transform.affine_inverse()); } - _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->view_count, cms, will_continue_color, will_continue_depth); + _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->scene_data->view_count, cms, will_continue_color, will_continue_depth); } if (draw_sky || draw_sky_fog_only) { @@ -1578,10 +1415,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (p_render_data->reflection_probe.is_valid()) { Projection correction; correction.set_depth_correction(true); - Projection projection = correction * p_render_data->cam_projection; - sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier); + Projection projection = correction * p_render_data->scene_data->cam_projection; + sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); } else { - sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier); + sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); } RD::get_singleton()->draw_command_end_label(); } @@ -1608,7 +1445,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (using_sss) { RENDER_TIMESTAMP("Sub-Surface Scattering"); RD::get_singleton()->draw_command_begin_label("Process Sub-Surface Scattering"); - _process_sss(rb, p_render_data->cam_projection); + _process_sss(rb, p_render_data->scene_data->cam_projection); RD::get_singleton()->draw_command_end_label(); } @@ -1616,15 +1453,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RENDER_TIMESTAMP("Screen-Space Reflections"); RD::get_singleton()->draw_command_begin_label("Process Screen-Space Reflections"); RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS]; - for (uint32_t v = 0; v < p_render_data->view_count; v++) { + for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) { specular_views[v] = rb_data->get_specular(v); } - _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED); + _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED); RD::get_singleton()->draw_command_end_label(); } else { //just mix specular back RENDER_TIMESTAMP("Merge Specular"); - copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->view_count); + copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->scene_data->view_count); } } @@ -1649,7 +1486,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co { uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR); RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer; - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count); _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); } @@ -1680,7 +1517,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (rb.is_valid() && taa && rb->get_use_taa()) { RENDER_TIMESTAMP("TAA") - taa->process(rb, _render_buffers_get_color_format(), p_render_data->z_near, p_render_data->z_far); + taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far); } if (rb.is_valid()) { @@ -1701,33 +1538,35 @@ void RenderForwardClustered::_render_shadow_begin() { scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) { +void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; + RenderSceneDataRD scene_data; + scene_data.cam_projection = p_projection; + scene_data.cam_transform = p_transform; + scene_data.view_projection[0] = p_projection; + scene_data.z_far = p_zfar; + scene_data.z_near = 0.0; + scene_data.lod_camera_plane = p_camera_plane; + scene_data.lod_distance_multiplier = p_lod_distance_multiplier; + scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; + scene_data.opaque_prepass_threshold = 0.1f; + RenderDataRD render_data; - render_data.cam_projection = p_projection; - render_data.cam_transform = p_transform; - render_data.view_projection[0] = p_projection; - render_data.z_far = p_zfar; - render_data.z_near = 0.0; + render_data.scene_data = &scene_data; render_data.cluster_size = 1; render_data.cluster_max_elements = 32; render_data.instances = &p_instances; - render_data.lod_camera_plane = p_camera_plane; - render_data.lod_distance_multiplier = p_lod_distance_multiplier; render_data.render_info = p_render_info; - scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - scene_state.ubo.opaque_prepass_threshold = 0.1f; - _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - render_data.screen_mesh_lod_threshold = 0.0; + scene_data.screen_mesh_lod_threshold = 0.0; } else { - render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; + scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; } PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; @@ -1752,8 +1591,8 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete shadow_pass.camera_plane = p_camera_plane; - shadow_pass.screen_mesh_lod_threshold = render_data.screen_mesh_lod_threshold; - shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier; + shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold; + shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier; shadow_pass.framebuffer = p_framebuffer; shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); @@ -1796,19 +1635,22 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); + RenderSceneDataRD scene_data; + scene_data.cam_projection = p_cam_projection; + scene_data.cam_transform = p_cam_transform; + scene_data.view_projection[0] = p_cam_projection; + scene_data.z_near = 0.0; + scene_data.z_far = p_cam_projection.get_z_far(); + scene_data.dual_paraboloid_side = 0; + scene_data.opaque_prepass_threshold = 0.0; + RenderDataRD render_data; - render_data.cam_projection = p_cam_projection; - render_data.cam_transform = p_cam_transform; - render_data.view_projection[0] = p_cam_projection; - render_data.z_near = 0.0; - render_data.z_far = p_cam_projection.get_z_far(); + render_data.scene_data = &scene_data; render_data.cluster_size = 1; render_data.cluster_max_elements = 32; render_data.instances = &p_instances; _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.opaque_prepass_threshold = 0.0; _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false); @@ -1835,21 +1677,23 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform RD::get_singleton()->draw_command_begin_label("Render 3D Material"); + RenderSceneDataRD scene_data; + scene_data.cam_projection = p_cam_projection; + scene_data.cam_transform = p_cam_transform; + scene_data.view_projection[0] = p_cam_projection; + scene_data.dual_paraboloid_side = 0; + scene_data.material_uv2_mode = false; + scene_data.opaque_prepass_threshold = 0.0f; + scene_data.emissive_exposure_normalization = p_exposure_normalization; + RenderDataRD render_data; - render_data.cam_projection = p_cam_projection; - render_data.cam_transform = p_cam_transform; - render_data.view_projection[0] = p_cam_projection; + render_data.scene_data = &scene_data; render_data.cluster_size = 1; render_data.cluster_max_elements = 32; render_data.instances = &p_instances; _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = false; - scene_state.ubo.opaque_prepass_threshold = 0.0f; - scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization; - _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; @@ -1885,18 +1729,20 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance RD::get_singleton()->draw_command_begin_label("Render UV2"); + RenderSceneDataRD scene_data; + scene_data.dual_paraboloid_side = 0; + scene_data.material_uv2_mode = true; + scene_data.opaque_prepass_threshold = 0.0; + scene_data.emissive_exposure_normalization = -1.0; + RenderDataRD render_data; + render_data.scene_data = &scene_data; render_data.cluster_size = 1; render_data.cluster_max_elements = 32; render_data.instances = &p_instances; _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = true; - scene_state.ubo.opaque_prepass_threshold = 0.0; - scene_state.ubo.emissive_exposure_normalization = -1.0; - _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; @@ -1956,7 +1802,10 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel"); + RenderSceneDataRD scene_data; + RenderDataRD render_data; + render_data.scene_data = &scene_data; render_data.cluster_size = 1; render_data.cluster_max_elements = 32; render_data.instances = &p_instances; @@ -1997,26 +1846,26 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu fb_size.x = p_size[right_axis]; fb_size.y = p_size[up_axis]; - render_data.cam_transform.origin = center + axis * half_extents; - render_data.cam_transform.basis.set_column(0, right); - render_data.cam_transform.basis.set_column(1, up); - render_data.cam_transform.basis.set_column(2, axis); + scene_data.cam_transform.origin = center + axis * half_extents; + scene_data.cam_transform.basis.set_column(0, right); + scene_data.cam_transform.basis.set_column(1, up); + scene_data.cam_transform.basis.set_column(2, axis); - //print_line("pass: " + itos(i) + " xform " + render_data.cam_transform); + //print_line("pass: " + itos(i) + " xform " + scene_data.cam_transform); float h_size = half_extents[right_axis]; float v_size = half_extents[up_axis]; float d_size = half_extents[i] * 2.0; - render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); + scene_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); //print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size)); Transform3D to_bounds; to_bounds.origin = p_bounds.position; to_bounds.basis.scale(p_bounds.size); - RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * render_data.cam_transform, scene_state.ubo.sdf_to_bounds); + RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * scene_data.cam_transform, scene_state.ubo.sdf_to_bounds); - scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization; + scene_data.emissive_exposure_normalization = p_exposure_normalization; _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); @@ -2258,6 +2107,13 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend { RD::Uniform u; u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.append_id(scene_state.implementation_uniform_buffers[p_index]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; RID instance_buffer = scene_state.instance_buffer[p_render_list]; if (instance_buffer == RID()) { @@ -2274,16 +2130,15 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); } RD::Uniform u; - u.binding = 2; + u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.append_id(radiance_texture); uniforms.push_back(u); } - { RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID(); RD::Uniform u; - u.binding = 3; + u.binding = 4; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (ref_texture.is_valid()) { u.append_id(ref_texture); @@ -2292,10 +2147,9 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend } uniforms.push_back(u); } - { RD::Uniform u; - u.binding = 4; + u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_render_data && p_render_data->shadow_atlas.is_valid()) { @@ -2309,7 +2163,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend } { RD::Uniform u; - u.binding = 5; + u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { u.append_id(directional_shadow_get_texture()); @@ -2320,7 +2174,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend } { RD::Uniform u; - u.binding = 6; + u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); @@ -2339,7 +2193,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend } { RD::Uniform u; - u.binding = 7; + u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) { @@ -2359,7 +2213,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend { RD::Uniform u; - u.binding = 8; + u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; RID cb = (p_render_data && p_render_data->cluster_buffer.is_valid()) ? p_render_data->cluster_buffer : scene_shader.default_vec4_xform_buffer; u.append_id(cb); @@ -2368,7 +2222,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend { RD::Uniform u; - u.binding = 9; + u.binding = 10; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) { @@ -2381,7 +2235,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend } { RD::Uniform u; - u.binding = 10; + u.binding = 11; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID(); RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); @@ -2390,110 +2244,108 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend } { - { - RD::Uniform u; - u.binding = 11; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL); - u.append_id(texture); - uniforms.push_back(u); - } + RD::Uniform u; + u.binding = 12; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL); + u.append_id(texture); + uniforms.push_back(u); + } - { - RD::Uniform u; - u.binding = 12; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID(); - RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); - u.append_id(texture); - uniforms.push_back(u); - } + { + RD::Uniform u; + u.binding = 13; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID(); + RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); + u.append_id(texture); + uniforms.push_back(u); + } - { - RD::Uniform u; - u.binding = 13; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); - u.append_id(texture); - uniforms.push_back(u); - } + { + RD::Uniform u; + u.binding = 14; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); + u.append_id(texture); + uniforms.push_back(u); + } - { - RD::Uniform u; - u.binding = 14; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); - u.append_id(texture); - uniforms.push_back(u); + { + RD::Uniform u; + u.binding = 15; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); + u.append_id(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 16; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID t; + if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { + Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); + t = sdfgi->lightprobe_texture; } - { - RD::Uniform u; - u.binding = 15; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID t; - if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { - Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); - t = sdfgi->lightprobe_texture; - } - if (t.is_null()) { - t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - } - u.append_id(t); - uniforms.push_back(u); + if (t.is_null()) { + t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); } - { - RD::Uniform u; - u.binding = 16; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID t; - if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { - Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); - t = sdfgi->occlusion_texture; - } - if (t.is_null()) { - t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); - } - u.append_id(t); - uniforms.push_back(u); + u.append_id(t); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 17; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID t; + if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { + Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); + t = sdfgi->occlusion_texture; } - { - RD::Uniform u; - u.binding = 17; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - RID voxel_gi; - if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) { - Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI); - voxel_gi = rbgi->get_voxel_gi_buffer(); - } - u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer()); - uniforms.push_back(u); + if (t.is_null()) { + t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); } - { - RD::Uniform u; - u.binding = 18; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID vfog = RID(); - if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) { - Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG); - vfog = fog->fog_map; - if (vfog.is_null()) { - vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); - } - } else { + u.append_id(t); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 18; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + RID voxel_gi; + if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) { + Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI); + voxel_gi = rbgi->get_voxel_gi_buffer(); + } + u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 19; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID vfog = RID(); + if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) { + Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG); + vfog = fog->fog_map; + if (vfog.is_null()) { vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); } - u.append_id(vfog); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 19; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID(); - RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); - u.append_id(texture); - uniforms.push_back(u); + } else { + vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); } + u.append_id(vfog); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 20; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID(); + RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); + u.append_id(texture); + uniforms.push_back(u); } return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, uniforms); @@ -2513,6 +2365,13 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { RD::Uniform u; u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.append_id(scene_state.implementation_uniform_buffers[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; RID instance_buffer = scene_state.instance_buffer[RENDER_LIST_SECONDARY]; if (instance_buffer == RID()) { @@ -2525,7 +2384,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te // No radiance texture. RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); RD::Uniform u; - u.binding = 2; + u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.append_id(radiance_texture); uniforms.push_back(u); @@ -2535,7 +2394,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te // No reflection atlas. RID ref_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); RD::Uniform u; - u.binding = 3; + u.binding = 4; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.append_id(ref_texture); uniforms.push_back(u); @@ -2544,7 +2403,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { // No shadow atlas. RD::Uniform u; - u.binding = 4; + u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH); u.append_id(texture); @@ -2554,7 +2413,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { // No directional shadow atlas. RD::Uniform u; - u.binding = 5; + u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH); u.append_id(texture); @@ -2564,7 +2423,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { // No Lightmaps RD::Uniform u; - u.binding = 6; + u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); @@ -2578,7 +2437,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { // No VoxelGIs RD::Uniform u; - u.binding = 7; + u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE); @@ -2591,7 +2450,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { RD::Uniform u; - u.binding = 8; + u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; RID cb = scene_shader.default_vec4_xform_buffer; u.append_id(cb); @@ -2603,28 +2462,28 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 9; + u.binding = 10; u.append_id(p_albedo_texture); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 10; + u.binding = 11; u.append_id(p_emission_texture); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 11; + u.binding = 12; u.append_id(p_emission_aniso_texture); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 12; + u.binding = 13; u.append_id(p_geom_facing_texture); uniforms.push_back(u); } @@ -2935,6 +2794,7 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_PARTICLES; ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; @@ -3205,6 +3065,9 @@ RenderForwardClustered::~RenderForwardClustered() { for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { RD::get_singleton()->free(scene_state.uniform_buffers[i]); } + for (uint32_t i = 0; i < scene_state.implementation_uniform_buffers.size(); i++) { + RD::get_singleton()->free(scene_state.implementation_uniform_buffers[i]); + } RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 9e2586542a..cde241f231 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -37,7 +37,7 @@ #include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" -#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h" #include "servers/rendering/renderer_rd/storage_rd/utilities.h" #define RB_SCOPE_FORWARD_CLUSTERED SNAME("forward_clustered") @@ -231,13 +231,14 @@ class RenderForwardClustered : public RendererSceneRenderRD { }; enum { - INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5, - INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, - INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, - INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, - INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, - INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11, + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4, + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5, + INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10, + INSTANCE_DATA_FLAG_PARTICLES = 1 << 11, INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, @@ -249,61 +250,22 @@ class RenderForwardClustered : public RendererSceneRenderRD { }; struct SceneState { - // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code + // This struct is loaded into Set 1 - Binding 1, populated at start of rendering a frame, must match with shader code struct UBO { - float projection_matrix[16]; - float inv_projection_matrix[16]; - float inv_view_matrix[16]; - float view_matrix[16]; - - float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; - float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; - float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4]; - - float viewport_size[2]; - float screen_pixel_size[2]; - uint32_t cluster_shift; uint32_t cluster_width; uint32_t cluster_type_size; uint32_t max_cluster_element_count_div_32; - float directional_penumbra_shadow_kernel[128]; //32 vec4s - float directional_soft_shadow_kernel[128]; - float penumbra_shadow_kernel[128]; - float soft_shadow_kernel[128]; - - float ambient_light_color_energy[4]; - - float ambient_color_sky_mix; - uint32_t use_ambient_light; - uint32_t use_ambient_cubemap; - uint32_t use_reflection_cubemap; - - float radiance_inverse_xform[12]; - - float shadow_atlas_pixel_size[2]; - float directional_shadow_pixel_size[2]; - - uint32_t directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - uint32_t ss_effects_flags; float ssao_light_affect; float ssao_ao_affect; - uint32_t roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - float opaque_prepass_threshold; - uint32_t roughness_limiter_pad; + uint32_t pad1; float sdf_to_bounds[16]; int32_t sdf_offset[3]; - uint32_t material_uv2_mode; + uint32_t pad2; int32_t sdf_size[3]; uint32_t gi_upscale_for_msaa; @@ -312,26 +274,6 @@ class RenderForwardClustered : public RendererSceneRenderRD { float volumetric_fog_inv_length; float volumetric_fog_detail_spread; uint32_t volumetric_fog_pad; - - // Fog - uint32_t fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - float fog_light_color[3]; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; - - uint32_t pancake_shadows; - - float taa_jitter[2]; - float emissive_exposure_normalization; // Needed to normalize emissive when using physical units. - float IBL_exposure_normalization; }; struct PushConstant { @@ -351,11 +293,10 @@ class RenderForwardClustered : public RendererSceneRenderRD { float lightmap_uv_scale[4]; }; - UBO ubo_data[2]; - UBO &ubo = ubo_data[0]; - UBO &prev_ubo = ubo_data[1]; + UBO ubo; LocalVector<RID> uniform_buffers; + LocalVector<RID> implementation_uniform_buffers; LightmapData lightmaps[MAX_LIGHTMAPS]; RID lightmap_ids[MAX_LIGHTMAPS]; @@ -623,7 +564,7 @@ protected: virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; virtual void _render_shadow_begin() override; - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override; virtual void _render_shadow_process() override; virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index c2f56eb164..a9a9fa94de 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -32,7 +32,7 @@ #define SCENE_SHADER_FORWARD_CLUSTERED_H #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" -#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h" namespace RendererSceneRenderImplementation { 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 46d90e75fb..6c1b69148c 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -504,8 +504,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RENDER_TIMESTAMP("Setup 3D Scene"); - scene_state.ubo.directional_light_count = 0; - scene_state.ubo.opaque_prepass_threshold = 0.0; + /* TODO + // check if we need motion vectors + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) { + p_render_data->scene_data->calculate_motion_vectors = true; + } else if (render target has velocity override) { // TODO + p_render_data->scene_data->calculate_motion_vectors = true; + } else { + p_render_data->scene_data->calculate_motion_vectors = false; + } + */ + p_render_data->scene_data->calculate_motion_vectors = false; // for now, not yet supported... + + p_render_data->scene_data->directional_light_count = 0; + p_render_data->scene_data->opaque_prepass_threshold = 0.0; // We can only use our full subpass approach if we're: // - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE @@ -581,13 +593,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color ERR_FAIL(); //bug? } - scene_state.ubo.viewport_size[0] = screen_size.x; - scene_state.ubo.viewport_size[1] = screen_size.y; - scene_state.ubo.emissive_exposure_normalization = -1.0; + p_render_data->scene_data->emissive_exposure_normalization = -1.0; RD::get_singleton()->draw_command_begin_label("Render Setup"); - _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform); + _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform); _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) @@ -658,20 +668,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); RD::get_singleton()->draw_command_begin_label("Setup Sky"); - Projection projection = p_render_data->cam_projection; + Projection projection = p_render_data->scene_data->cam_projection; if (p_render_data->reflection_probe.is_valid()) { Projection correction; correction.set_depth_correction(true); - projection = correction * p_render_data->cam_projection; + projection = correction * p_render_data->scene_data->cam_projection; } - sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this); + sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this); sky_energy_multiplier *= bg_energy_multiplier; RID sky_rid = environment_get_sky(p_render_data->environment); if (sky_rid.is_valid()) { - sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier); + sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid); } else { // do not try to draw sky if invalid @@ -694,10 +704,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (p_render_data->reflection_probe.is_valid()) { Projection correction; correction.set_depth_correction(true); - Projection projection = correction * p_render_data->cam_projection; - sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier); + Projection projection = correction * p_render_data->scene_data->cam_projection; + sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); } else { - sky.update_res_buffers(p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier); + sky.update_res_buffers(p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); } RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers @@ -719,7 +729,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS; } - if (!is_environment(p_render_data->environment) || environment_get_fog_enabled(p_render_data->environment)) { + if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) { spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG; } } @@ -734,7 +744,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass"); - scene_state.ubo.directional_light_count = p_render_data->directional_light_count; + p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count; _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid()); @@ -765,7 +775,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count); render_list_params.framebuffer_format = fb_format; if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time @@ -793,10 +803,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (p_render_data->reflection_probe.is_valid()) { Projection correction; correction.set_depth_correction(true); - Projection projection = correction * p_render_data->cam_projection; - sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier); + Projection projection = correction * p_render_data->scene_data->cam_projection; + sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); } else { - sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier); + sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier); } RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass @@ -832,7 +842,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (using_subpass_transparent) { RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count); render_list_params.framebuffer_format = fb_format; if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time @@ -871,7 +881,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color // _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count); render_list_params.framebuffer_format = fb_format; if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time @@ -919,7 +929,7 @@ void RenderForwardMobile::_render_shadow_begin() { render_list[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) { +void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RenderingMethod::RenderInfo *p_render_info) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; @@ -928,26 +938,29 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_instances.size(); p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_instances.size(); } + + RenderSceneDataRD scene_data; + scene_data.cam_projection = p_projection; + scene_data.cam_transform = p_transform; + scene_data.view_projection[0] = p_projection; + scene_data.z_near = 0.0; + scene_data.z_far = p_zfar; + scene_data.lod_camera_plane = p_camera_plane; + scene_data.lod_distance_multiplier = p_lod_distance_multiplier; + scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; + scene_data.opaque_prepass_threshold = 0.1; + RenderDataRD render_data; - render_data.cam_projection = p_projection; - render_data.cam_transform = p_transform; - render_data.view_projection[0] = p_projection; - render_data.z_near = 0.0; - render_data.z_far = p_zfar; + render_data.scene_data = &scene_data; render_data.instances = &p_instances; render_data.render_info = p_render_info; - render_data.lod_camera_plane = p_camera_plane; - render_data.lod_distance_multiplier = p_lod_distance_multiplier; - - scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - scene_state.ubo.opaque_prepass_threshold = 0.1; _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - render_data.screen_mesh_lod_threshold = 0.0; + scene_data.screen_mesh_lod_threshold = 0.0; } else { - render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; + scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; } PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; @@ -972,8 +985,8 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete shadow_pass.camera_plane = p_camera_plane; - shadow_pass.screen_mesh_lod_threshold = render_data.screen_mesh_lod_threshold; - shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier; + shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold; + shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier; shadow_pass.framebuffer = p_framebuffer; shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); @@ -1020,15 +1033,17 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = false; - scene_state.ubo.opaque_prepass_threshold = 0.0f; - scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization; + RenderSceneDataRD scene_data; + scene_data.cam_projection = p_cam_projection; + scene_data.cam_transform = p_cam_transform; + scene_data.view_projection[0] = p_cam_projection; + scene_data.dual_paraboloid_side = 0; + scene_data.material_uv2_mode = false; + scene_data.opaque_prepass_threshold = 0.0f; + scene_data.emissive_exposure_normalization = p_exposure_normalization; RenderDataRD render_data; - render_data.cam_projection = p_cam_projection; - render_data.cam_transform = p_cam_transform; - render_data.view_projection[0] = p_cam_projection; + render_data.scene_data = &scene_data; render_data.instances = &p_instances; _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -1067,11 +1082,13 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = true; - scene_state.ubo.emissive_exposure_normalization = -1.0; + RenderSceneDataRD scene_data; + scene_data.dual_paraboloid_side = 0; + scene_data.material_uv2_mode = true; + scene_data.emissive_exposure_normalization = -1.0; RenderDataRD render_data; + render_data.scene_data = &scene_data; render_data.instances = &p_instances; _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -1138,15 +1155,18 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.opaque_prepass_threshold = 0.0; + + RenderSceneDataRD scene_data; + scene_data.cam_projection = p_cam_projection; + scene_data.cam_transform = p_cam_transform; + scene_data.view_projection[0] = p_cam_projection; + scene_data.z_near = 0.0; + scene_data.z_far = p_cam_projection.get_z_far(); + scene_data.dual_paraboloid_side = 0; + scene_data.opaque_prepass_threshold = 0.0; RenderDataRD render_data; - render_data.cam_projection = p_cam_projection; - render_data.cam_transform = p_cam_transform; - render_data.view_projection[0] = p_cam_projection; - render_data.z_near = 0.0; - render_data.z_far = p_cam_projection.get_z_far(); + render_data.scene_data = &scene_data; render_data.instances = &p_instances; _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false); @@ -1385,9 +1405,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const } uint32_t lightmap_captures_used = 0; - Plane near_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin); - near_plane.d += p_render_data->cam_projection.get_z_near(); - float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near(); + Plane near_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); + near_plane.d += p_render_data->scene_data->cam_projection.get_z_near(); + float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near(); RenderList *rl = &render_list[p_render_list]; @@ -1466,13 +1486,13 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const // LOD - if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) { + if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) { //lod - Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal); - Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal); + Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->scene_data->lod_camera_plane.normal); + Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal); - float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min); - float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max); + float distance_min = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_min); + float distance_max = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_max); float distance = 0.0; @@ -1485,12 +1505,12 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const distance = -distance_max; } - if (p_render_data->cam_orthogonal) { + if (p_render_data->scene_data->cam_orthogonal) { distance = 1.0; } uint32_t indices; - surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices); + surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices); if (p_render_data->render_info) { indices = _indices_to_primitives(surf->primitive, indices); if (p_render_list == RENDER_LIST_OPAQUE) { //opaque @@ -1562,184 +1582,20 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const } void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { - //!BAS! need to go through this and find out what we don't need anymore - - // This populates our UBO with main scene data that is pushed into set 1 - - //Projection projection = p_render_data->cam_projection; - //projection.flip_y(); // Vulkan and modern APIs use Y-Down - Projection correction; - correction.set_depth_correction(p_flip_y); - Projection projection = correction * p_render_data->cam_projection; - - //store camera into ubo - RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix); - RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix); - RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix); - - for (uint32_t v = 0; v < p_render_data->view_count; v++) { - projection = correction * p_render_data->view_projection[v]; - RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix_view[v]); - RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]); - - scene_state.ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x; - scene_state.ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y; - scene_state.ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z; - scene_state.ubo.eye_offset[v][3] = 0.0; - } - - scene_state.ubo.z_far = p_render_data->z_far; - scene_state.ubo.z_near = p_render_data->z_near; - - scene_state.ubo.pancake_shadows = p_pancake_shadows; - - RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); - RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); - RendererRD::MaterialStorage::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); - RendererRD::MaterialStorage::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); - - Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); - scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; - scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; - - if (p_render_data->shadow_atlas.is_valid()) { - Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas); - scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; - scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; - } - { - Vector2 dss = directional_shadow_get_size(); - scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x; - scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y; - } - - //time global variables - scene_state.ubo.time = time; - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - scene_state.ubo.use_ambient_light = true; - scene_state.ubo.ambient_light_color_energy[0] = 1; - scene_state.ubo.ambient_light_color_energy[1] = 1; - scene_state.ubo.ambient_light_color_energy[2] = 1; - scene_state.ubo.ambient_light_color_energy[3] = 1.0; - scene_state.ubo.use_ambient_cubemap = false; - scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; - - } else if (is_environment(p_render_data->environment)) { - RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment); - RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment); - - float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment); - - scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier; - - scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment); - - //ambient - if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { - Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment); - color = color.srgb_to_linear(); - - scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier; - scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier; - scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier; - scene_state.ubo.use_ambient_light = true; - scene_state.ubo.use_ambient_cubemap = false; - } else { - float energy = environment_get_ambient_light_energy(p_render_data->environment); - Color color = environment_get_ambient_light(p_render_data->environment); - color = color.srgb_to_linear(); - scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; - scene_state.ubo.ambient_light_color_energy[1] = color.g * energy; - scene_state.ubo.ambient_light_color_energy[2] = color.b * energy; - - Basis sky_transform = environment_get_sky_orientation(p_render_data->environment); - sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis; - RendererRD::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); - - scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; - scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; - } - - //specular - RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment); - if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { - scene_state.ubo.use_reflection_cubemap = true; - } else { - scene_state.ubo.use_reflection_cubemap = false; - } - - scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_get_ssao_enabled(p_render_data->environment); - scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_channel_affect(p_render_data->environment); - scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment); - - scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment); - scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); - scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment); - scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment); - scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment); - - Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear(); - float fog_energy = environment_get_fog_light_energy(p_render_data->environment); - - scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; - scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; - scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; - - scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment); - - } else { - if (p_render_data->reflection_probe.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { - scene_state.ubo.use_ambient_light = false; - } else { - scene_state.ubo.use_ambient_light = true; - Color clear_color = p_default_bg_color; - clear_color = clear_color.srgb_to_linear(); - scene_state.ubo.ambient_light_color_energy[0] = clear_color.r; - scene_state.ubo.ambient_light_color_energy[1] = clear_color.g; - scene_state.ubo.ambient_light_color_energy[2] = clear_color.b; - scene_state.ubo.ambient_light_color_energy[3] = 1.0; - } - - scene_state.ubo.use_ambient_cubemap = false; - scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; - } - - if (p_render_data->camera_attributes.is_valid()) { - scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes); - scene_state.ubo.IBL_exposure_normalization = 1.0; - if (is_environment(p_render_data->environment)) { - RID sky_rid = environment_get_sky(p_render_data->environment); - if (sky_rid.is_valid()) { - float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier(); - scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid)); - } - } - } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) { - // This branch is triggered when using render_material(). - // Emissive is set outside the function, so don't set it. - // IBL isn't used don't set it. - } else { - scene_state.ubo.emissive_exposure_normalization = 1.0; - scene_state.ubo.IBL_exposure_normalization = 1.0; - } - - scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); - scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); - scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); + Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers; + RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID(); + RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID(); + // May do this earlier in RenderSceneRenderRD::render_scene if (p_index >= (int)scene_state.uniform_buffers.size()) { uint32_t from = scene_state.uniform_buffers.size(); scene_state.uniform_buffers.resize(p_index + 1); - render_pass_uniform_sets.resize(p_index + 1); for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { - scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); + scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer(); } } - RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); + + p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers); } void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index da1cd85fb3..1b31d2749d 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -209,7 +209,7 @@ protected: virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; virtual void _render_shadow_begin() override; - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override; virtual void _render_shadow_process() override; virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override; @@ -252,75 +252,6 @@ protected: /* Scene state */ struct SceneState { - // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code - struct UBO { - float projection_matrix[16]; - float inv_projection_matrix[16]; - float inv_view_matrix[16]; - float view_matrix[16]; - - float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; - float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; - float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4]; - - float viewport_size[2]; - float screen_pixel_size[2]; - - float directional_penumbra_shadow_kernel[128]; //32 vec4s - float directional_soft_shadow_kernel[128]; - float penumbra_shadow_kernel[128]; - float soft_shadow_kernel[128]; - - float ambient_light_color_energy[4]; - - float ambient_color_sky_mix; - uint32_t use_ambient_light; - uint32_t use_ambient_cubemap; - uint32_t use_reflection_cubemap; - - float radiance_inverse_xform[12]; - - float shadow_atlas_pixel_size[2]; - float directional_shadow_pixel_size[2]; - - uint32_t directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - - uint32_t ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; - uint32_t roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - float opaque_prepass_threshold; - uint32_t roughness_limiter_pad; - - // Fog - uint32_t fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - float fog_light_color[3]; - float fog_sun_scatter; - - float fog_aerial_perspective; - uint32_t material_uv2_mode; - - float time; - float reflection_multiplier; - - uint32_t pancake_shadows; - float emissive_exposure_normalization; // Needed to normalize emissive when using physical units. - float IBL_exposure_normalization; // Adjusts for baked exposure. - uint32_t pad3; - }; - - UBO ubo; - LocalVector<RID> uniform_buffers; // !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in @@ -442,13 +373,14 @@ protected: // check which ones of these apply, probably all except GI and SDFGI enum { - INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5, - INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, - INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, - INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, - INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, - INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11, + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4, + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5, + INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10, + INSTANCE_DATA_FLAG_PARTICLES = 1 << 11, INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, 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 21270d7c62..f67665a02f 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 @@ -32,7 +32,7 @@ #define SCENE_SHADER_FORWARD_MOBILE_H #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" -#include "servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl.gen.h" namespace RendererSceneRenderImplementation { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index ab3e3ebe51..0210151420 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1362,9 +1362,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p default_repeat = p_default_repeat; } - //fill the list until rendering is possible. - bool material_screen_texture_found = false; Item *ci = p_item_list; + + //fill the list until rendering is possible. + bool material_screen_texture_cached = false; + bool material_screen_texture_mipmaps_cached = false; + Rect2 back_buffer_rect; bool backbuffer_copy = false; bool backbuffer_gen_mipmaps = false; @@ -1393,10 +1396,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p CanvasMaterialData *md = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::MaterialStorage::SHADER_TYPE_2D)); if (md && md->shader_data->valid) { if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { - if (!material_screen_texture_found) { + if (!material_screen_texture_cached) { backbuffer_copy = true; back_buffer_rect = Rect2(); backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps; + } else if (!material_screen_texture_mipmaps_cached) { + backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps; } } @@ -1486,7 +1491,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p backbuffer_copy = false; backbuffer_gen_mipmaps = false; - material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies + material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies. + material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps; + } + + if (backbuffer_gen_mipmaps) { + texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect); + + backbuffer_gen_mipmaps = false; + material_screen_texture_mipmaps_cached = true; } items[item_count++] = ci; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index e7abcf5674..f169692ea0 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -299,14 +299,19 @@ RendererCompositorRD::RendererCompositorRD() { fog = memnew(RendererRD::Fog); canvas = memnew(RendererCanvasRenderRD()); - back_end = (bool)(int)GLOBAL_GET("rendering/vulkan/rendering/back_end"); + String rendering_method = GLOBAL_GET("rendering/renderer/rendering_method"); uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); - if (back_end || textures_per_stage < 48) { + if (rendering_method == "mobile" || textures_per_stage < 48) { scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile()); - } else { // back_end == false + if (rendering_method == "forward_plus") { + WARN_PRINT_ONCE("Platform supports less than 48 textures per stage which is less than required by the Clustered renderer. Defaulting to Mobile renderer."); + } + } else if (rendering_method == "forward_plus") { // default to our high end renderer scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered()); + } else { + ERR_FAIL_MSG("Cannot instantiate RenderingDevice-based renderer with renderer type " + rendering_method); } scene->init(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index e2b06bc92f..2190f41603 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1492,7 +1492,7 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR bool can_use_storage = _render_buffers_can_be_storage(); Size2i size = rb->get_internal_size(); - for (uint32_t v = 0; v < p_render_data->view_count; v++) { + for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) { RID depth_texture = rb->get_depth_texture(v); RID depth_back_texture = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, v, 0); @@ -1544,9 +1544,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende buffers.depth_texture = rb->get_depth_texture(i); // In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum - float z_near = p_render_data->view_projection[i].get_z_near(); - float z_far = p_render_data->view_projection[i].get_z_far(); - bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal); + float z_near = p_render_data->scene_data->view_projection[i].get_z_near(); + float z_far = p_render_data->scene_data->view_projection[i].get_z_far(); + bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal); }; } else { // Set framebuffers. @@ -1567,9 +1567,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende buffers.base_fb = FramebufferCacheRD::get_singleton()->get_cache(buffers.base_texture); // TODO move this into bokeh_dof_raster, we can do this internally // In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum - float z_near = p_render_data->view_projection[i].get_z_near(); - float z_far = p_render_data->view_projection[i].get_z_far(); - bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal); + float z_near = p_render_data->scene_data->view_projection[i].get_z_near(); + float z_far = p_render_data->scene_data->view_projection[i].get_z_far(); + bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal); } } RD::get_singleton()->draw_command_end_label(); @@ -2901,8 +2901,8 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool render_state.shadows.clear(); render_state.directional_shadows.clear(); - Plane camera_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin); - float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier(); + Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin); + float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier(); { for (int i = 0; i < render_state.render_shadow_count; i++) { LightInstance *li = light_instance_owner.get_or_null(render_state.render_shadows[i].light); @@ -2918,7 +2918,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //cube shadows are rendered in their own way for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.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); } if (render_state.directional_shadows.size()) { @@ -2948,11 +2948,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //render directional shadows for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info); + _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info); } //render positional shadows for (uint32_t i = 0; i < render_state.shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info); + _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info); } _render_shadow_process(); @@ -2960,7 +2960,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //start GI if (render_gi) { - gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances); + gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances); } //Do shadow rendering (in parallel with GI) @@ -2999,17 +2999,17 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } RID depth_texture = rb->get_depth_texture(); - ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->cam_projection); + ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->scene_data->cam_projection); } if (p_use_ssao) { // TODO make these proper stereo - _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection); + _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection); } if (p_use_ssil) { // TODO make these proper stereo - _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection, p_render_data->cam_transform); + _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform); } } @@ -3017,7 +3017,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); if (current_cluster_builder) { - current_cluster_builder->begin(p_render_data->cam_transform, p_render_data->cam_projection, !p_render_data->reflection_probe.is_valid()); + current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid()); } bool using_shadows = true; @@ -3028,13 +3028,13 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } } else { //do not render reflections when rendering a reflection probe - _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment); + _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment); } uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; - _setup_lights(p_render_data, *p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - _setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse()); + _setup_lights(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); + _setup_decals(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); p_render_data->directional_light_count = directional_light_count; @@ -3051,12 +3051,12 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } } if (is_volumetric_supported()) { - _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes); + _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes); } } } -void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { +void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); // getting this here now so we can direct call a bunch of things more easily @@ -3066,33 +3066,62 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render ERR_FAIL_COND(rb.is_null()); } - //assign render data - RenderDataRD render_data; + // setup scene data + RenderSceneDataRD scene_data; { - render_data.render_buffers = rb; - // Our first camera is used by default - render_data.cam_transform = p_camera_data->main_transform; - render_data.cam_projection = p_camera_data->main_projection; - render_data.cam_orthogonal = p_camera_data->is_orthogonal; - render_data.taa_jitter = p_camera_data->taa_jitter; + scene_data.cam_transform = p_camera_data->main_transform; + scene_data.cam_projection = p_camera_data->main_projection; + scene_data.cam_orthogonal = p_camera_data->is_orthogonal; + scene_data.taa_jitter = p_camera_data->taa_jitter; - render_data.view_count = p_camera_data->view_count; + scene_data.view_count = p_camera_data->view_count; for (uint32_t v = 0; v < p_camera_data->view_count; v++) { - render_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin; - render_data.view_projection[v] = p_camera_data->view_projection[v]; + scene_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin; + scene_data.view_projection[v] = p_camera_data->view_projection[v]; } - render_data.prev_cam_transform = p_prev_camera_data->main_transform; - render_data.prev_cam_projection = p_prev_camera_data->main_projection; - render_data.prev_taa_jitter = p_prev_camera_data->taa_jitter; + scene_data.prev_cam_transform = p_prev_camera_data->main_transform; + scene_data.prev_cam_projection = p_prev_camera_data->main_projection; + scene_data.prev_taa_jitter = p_prev_camera_data->taa_jitter; for (uint32_t v = 0; v < p_camera_data->view_count; v++) { - render_data.prev_view_projection[v] = p_prev_camera_data->view_projection[v]; + scene_data.prev_view_projection[v] = p_prev_camera_data->view_projection[v]; + } + + scene_data.z_near = p_camera_data->main_projection.get_z_near(); + scene_data.z_far = p_camera_data->main_projection.get_z_far(); + + // this should be the same for all cameras.. + scene_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier(); + scene_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin()); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + scene_data.screen_mesh_lod_threshold = 0.0; + } else { + scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; + } + + if (p_shadow_atlas.is_valid()) { + Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); + scene_data.shadow_atlas_pixel_size.x = 1.0 / sas.x; + scene_data.shadow_atlas_pixel_size.y = 1.0 / sas.y; } + { + Vector2 dss = directional_shadow_get_size(); + scene_data.directional_shadow_pixel_size.x = 1.0 / dss.x; + scene_data.directional_shadow_pixel_size.y = 1.0 / dss.y; + } + + scene_data.time = time; + scene_data.time_step = time_step; + } - render_data.z_near = p_camera_data->main_projection.get_z_near(); - render_data.z_far = p_camera_data->main_projection.get_z_far(); + //assign render data + RenderDataRD render_data; + { + render_data.render_buffers = rb; + render_data.scene_data = &scene_data; render_data.instances = &p_instances; render_data.lights = &p_lights; @@ -3108,16 +3137,6 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render render_data.reflection_probe = p_reflection_probe; render_data.reflection_probe_pass = p_reflection_probe_pass; - // this should be the same for all cameras.. - render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier(); - render_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin()); - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - render_data.screen_mesh_lod_threshold = 0.0; - } else { - render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold; - } - render_state.render_shadows = p_render_shadows; render_state.render_shadow_count = p_render_shadow_count; render_state.render_sdfgi_regions = p_render_sdfgi_regions; @@ -3134,7 +3153,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render render_data.voxel_gi_instances = ∅ } - //sdfgi first + // sdfgi first if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); float exposure_normalization = 1.0; @@ -3191,12 +3210,12 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); if (sdfgi.is_valid()) { sdfgi->update_cascades(); - sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this); + sdfgi->pre_process_gi(scene_data.cam_transform, &render_data, this); sdfgi->update_light(); } } - gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this); + gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, scene_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this); } render_state.depth_prepass_used = false; @@ -3246,7 +3265,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render view_rids.push_back(rb->get_internal_texture(v)); } - sdfgi->debug_draw(render_data.view_count, render_data.view_projection, render_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids); + sdfgi->debug_draw(scene_data.view_count, scene_data.view_projection, scene_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids); } } } @@ -3278,7 +3297,7 @@ void RendererSceneRenderRD::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_rend } } -void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RendererScene::RenderInfo *p_render_info) { +void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) { LightInstance *light_instance = light_instance_owner.get_or_null(p_light); ERR_FAIL_COND(!light_instance); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index d47394989f..82dc2fd09f 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -46,30 +46,14 @@ #include "servers/rendering/renderer_rd/environment/sky.h" #include "servers/rendering/renderer_rd/framebuffer_cache_rd.h" #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" -#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" +#include "servers/rendering/rendering_method.h" struct RenderDataRD { Ref<RenderSceneBuffersRD> render_buffers; - - Transform3D cam_transform; - Projection cam_projection; - Vector2 taa_jitter; - bool cam_orthogonal = false; - - // For stereo rendering - uint32_t view_count = 1; - Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS]; - Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; - - Transform3D prev_cam_transform; - Projection prev_cam_projection; - Vector2 prev_taa_jitter; - Projection prev_view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; - - float z_near = 0.0; - float z_far = 0.0; + RenderSceneDataRD *scene_data; const PagedArray<RenderGeometryInstance *> *instances = nullptr; const PagedArray<RID> *lights = nullptr; @@ -85,10 +69,6 @@ struct RenderDataRD { RID reflection_probe; int reflection_probe_pass = 0; - float lod_distance_multiplier = 0.0; - Plane lod_camera_plane; - float screen_mesh_lod_threshold = 0.0; - RID cluster_buffer; uint32_t cluster_size = 0; uint32_t cluster_max_elements = 0; @@ -96,7 +76,7 @@ struct RenderDataRD { uint32_t directional_light_count = 0; bool directional_light_soft_shadows = false; - RendererScene::RenderInfo *render_info = nullptr; + RenderingMethod::RenderInfo *render_info = nullptr; }; class RendererSceneRenderRD : public RendererSceneRender { @@ -121,7 +101,7 @@ protected: virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0; virtual void _render_shadow_begin() = 0; - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) = 0; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) = 0; virtual void _render_shadow_process() = 0; virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0; @@ -598,16 +578,9 @@ private: uint64_t scene_pass = 0; uint64_t shadow_atlas_realloc_tolerance_msec = 500; - /* !BAS! is this used anywhere? - struct SDFGICosineNeighbour { - uint32_t neighbour; - float weight; - }; - */ - uint32_t max_cluster_elements = 512; - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RendererScene::RenderInfo *p_render_info = nullptr); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); /* Volumetric Fog */ @@ -627,6 +600,10 @@ public: RendererRD::GI *get_gi() { return &gi; } + /* SKY */ + + RendererRD::SkyRD *get_sky() { return &sky; } + /* SHADOW ATLAS API */ virtual RID shadow_atlas_create() override; @@ -969,7 +946,7 @@ public: virtual void update_uniform_sets(){}; - virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; + virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index d352743908..5405985741 100644 --- a/servers/rendering/renderer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -18,3 +18,5 @@ if "RD_GLSL" in env["BUILDERS"]: SConscript("effects/SCsub") SConscript("environment/SCsub") +SConscript("forward_clustered/SCsub") +SConscript("forward_mobile/SCsub") diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub new file mode 100644 index 0000000000..741da8fe69 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import("env") + +if "RD_GLSL" in env["BUILDERS"]: + # find all include files + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + + # find all shader code(all glsl files excluding our include files) + glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] + + # make sure we recompile shaders if include files change + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"]) + + # compile shaders + for glsl_file in glsl_files: + env.RD_GLSL(glsl_file) diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 8e8ec6883a..d41474118d 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -326,10 +326,6 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime vertex_interp = vertex; -#ifdef MOTION_VECTORS - screen_pos = projection_matrix * vec4(vertex_interp, 1.0); -#endif - #ifdef NORMAL_USED normal_interp = normal; #endif @@ -367,6 +363,10 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime gl_Position = projection_matrix * vec4(vertex_interp, 1.0); #endif +#ifdef MOTION_VECTORS + screen_pos = gl_Position; +#endif + #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { if (gl_Position.z <= 0.00001) { @@ -553,7 +553,7 @@ layout(location = 0) out vec4 frag_color; layout(location = 2) out vec2 motion_vector; #endif -#include "scene_forward_aa_inc.glsl" +#include "../scene_forward_aa_inc.glsl" #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) @@ -562,20 +562,20 @@ layout(location = 2) out vec2 motion_vector; #define SPECULAR_SCHLICK_GGX #endif -#include "scene_forward_lights_inc.glsl" +#include "../scene_forward_lights_inc.glsl" -#include "scene_forward_gi_inc.glsl" +#include "../scene_forward_gi_inc.glsl" #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifndef MODE_RENDER_DEPTH vec4 volumetric_fog_process(vec2 screen_uv, float z) { - vec3 fog_pos = vec3(screen_uv, z * scene_data_block.data.volumetric_fog_inv_length); + vec3 fog_pos = vec3(screen_uv, z * implementation_data.volumetric_fog_inv_length); if (fog_pos.z < 0.0) { return vec4(0.0); } else if (fog_pos.z < 1.0) { - fog_pos.z = pow(fog_pos.z, scene_data_block.data.volumetric_fog_detail_spread); + fog_pos.z = pow(fog_pos.z, implementation_data.volumetric_fog_detail_spread); } return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); @@ -821,7 +821,7 @@ void fragment_shader(in SceneData scene_data) { fog = fog_process(vertex); } - if (scene_data.volumetric_fog_enabled) { + if (implementation_data.volumetric_fog_enabled) { vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z); if (scene_data.fog_enabled) { //must use the full blending equation here to blend fogs @@ -849,8 +849,8 @@ void fragment_shader(in SceneData scene_data) { #ifndef MODE_RENDER_DEPTH - uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift; - uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32); + uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> implementation_data.cluster_shift; + uint cluster_offset = (implementation_data.cluster_width * cluster_pos.y + cluster_pos.x) * (implementation_data.max_cluster_element_count_div_32 + 32); uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0)); @@ -860,14 +860,14 @@ void fragment_shader(in SceneData scene_data) { { // process decals - uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2; + uint cluster_decal_offset = cluster_offset + implementation_data.cluster_type_size * 2; uint item_min; uint item_max; uint item_from; uint item_to; - cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + cluster_get_item_range(cluster_decal_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); #ifdef USE_SUBGROUPS item_from = subgroupBroadcastFirst(subgroupMin(item_from)); @@ -1256,7 +1256,7 @@ void fragment_shader(in SceneData scene_data) { vec2 coord; - if (scene_data.gi_upscale_for_msaa) { + if (implementation_data.gi_upscale_for_msaa) { vec2 base_coord = screen_uv; vec2 closest_coord = base_coord; #ifdef USE_MULTIVIEW @@ -1298,10 +1298,10 @@ void fragment_shader(in SceneData scene_data) { } #endif // !USE_LIGHTMAP - if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) { + if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) { float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; ao = min(ao, ssao); - ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); + ao_light_affect = mix(ao_light_affect, max(ao_light_affect, implementation_data.ssao_light_affect), implementation_data.ssao_ao_affect); } { // process reflections @@ -1309,14 +1309,14 @@ void fragment_shader(in SceneData scene_data) { vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3; + uint cluster_reflection_offset = cluster_offset + implementation_data.cluster_type_size * 3; uint item_min; uint item_max; uint item_from; uint item_to; - cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + cluster_get_item_range(cluster_reflection_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); #ifdef USE_SUBGROUPS item_from = subgroupBroadcastFirst(subgroupMin(item_from)); @@ -1380,7 +1380,7 @@ void fragment_shader(in SceneData scene_data) { // convert ao to direct light ao ao = mix(1.0, ao, ao_light_affect); - if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) { + if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) { vec4 ssil = textureLod(sampler2D(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv, 0.0); ambient_light *= 1.0 - ssil.a; ambient_light += ssil.rgb * albedo.rgb; @@ -1748,7 +1748,7 @@ void fragment_shader(in SceneData scene_data) { uint item_from; uint item_to; - cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + cluster_get_item_range(cluster_omni_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); #ifdef USE_SUBGROUPS item_from = subgroupBroadcastFirst(subgroupMin(item_from)); @@ -1812,14 +1812,14 @@ void fragment_shader(in SceneData scene_data) { { //spot lights - uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; + uint cluster_spot_offset = cluster_offset + implementation_data.cluster_type_size; uint item_min; uint item_max; uint item_from; uint item_to; - cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + cluster_get_item_range(cluster_spot_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); #ifdef USE_SUBGROUPS item_from = subgroupBroadcastFirst(subgroupMin(item_from)); @@ -1909,8 +1909,8 @@ void fragment_shader(in SceneData scene_data) { #ifdef MODE_RENDER_SDF { - vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; - ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); + vec3 local_pos = (implementation_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; + ivec3 grid_pos = implementation_data.sdf_offset + ivec3(local_pos * vec3(implementation_data.sdf_size)); uint albedo16 = 0x1; //solid flag albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index d97da0c571..e8e2dce990 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -17,8 +17,9 @@ #extension GL_EXT_multiview : enable #endif -#include "cluster_data_inc.glsl" -#include "decal_data_inc.glsl" +#include "../cluster_data_inc.glsl" +#include "../decal_data_inc.glsl" +#include "../scene_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) #ifndef NORMAL_USED @@ -38,7 +39,7 @@ draw_call; /* Set 0: Base Pass (never changes) */ -#include "light_data_inc.glsl" +#include "../light_data_inc.glsl" #define SAMPLER_NEAREST_CLAMP 0 #define SAMPLER_LINEAR_CLAMP 1 @@ -175,62 +176,27 @@ sdfgi; /* Set 1: Render Pass (changes per render pass) */ -struct SceneData { - mat4 projection_matrix; - mat4 inv_projection_matrix; - mat4 inv_view_matrix; - mat4 view_matrix; - - // only used for multiview - mat4 projection_matrix_view[MAX_VIEWS]; - mat4 inv_projection_matrix_view[MAX_VIEWS]; - vec4 eye_offset[MAX_VIEWS]; - - vec2 viewport_size; - vec2 screen_pixel_size; +layout(set = 1, binding = 0, std140) uniform SceneDataBlock { + SceneData data; + SceneData prev_data; +} +scene_data_block; +struct ImplementationData { uint cluster_shift; uint cluster_width; uint cluster_type_size; uint max_cluster_element_count_div_32; - // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted. - vec4 directional_penumbra_shadow_kernel[32]; - vec4 directional_soft_shadow_kernel[32]; - vec4 penumbra_shadow_kernel[32]; - vec4 soft_shadow_kernel[32]; - - vec4 ambient_light_color_energy; - - float ambient_color_sky_mix; - bool use_ambient_light; - bool use_ambient_cubemap; - bool use_reflection_cubemap; - - mat3 radiance_inverse_xform; - - vec2 shadow_atlas_pixel_size; - vec2 directional_shadow_pixel_size; - - uint directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - uint ss_effects_flags; float ssao_light_affect; float ssao_ao_affect; - bool roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - float opaque_prepass_threshold; - uint roughness_limiter_pad; + uint pad1; mat4 sdf_to_bounds; ivec3 sdf_offset; - bool material_uv2_mode; + uint pad2; ivec3 sdf_size; bool gi_upscale_for_msaa; @@ -239,31 +205,14 @@ struct SceneData { float volumetric_fog_inv_length; float volumetric_fog_detail_spread; uint volumetric_fog_pad; - - bool fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - vec3 fog_light_color; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; // one normally, zero when rendering reflections - - bool pancake_shadows; - vec2 taa_jitter; - float emissive_exposure_normalization; - float IBL_exposure_normalization; }; -layout(set = 1, binding = 0, std140) uniform SceneDataBlock { - SceneData data; - SceneData prev_data; +layout(set = 1, binding = 1, std140) uniform ImplementationDataBlock { + ImplementationData data; } -scene_data_block; +implementation_data_block; + +#define implementation_data implementation_data_block.data struct InstanceData { mat4 transform; @@ -275,42 +224,42 @@ struct InstanceData { vec4 lightmap_uv_scale; }; -layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer { +layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer { InstanceData data[]; } instances; #ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 3) uniform textureCubeArray radiance_cubemap; #else -layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; +layout(set = 1, binding = 3) uniform textureCube radiance_cubemap; #endif -layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 4) uniform textureCubeArray reflection_atlas; -layout(set = 1, binding = 4) uniform texture2D shadow_atlas; +layout(set = 1, binding = 5) uniform texture2D shadow_atlas; -layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; +layout(set = 1, binding = 6) uniform texture2D directional_shadow_atlas; -layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; +layout(set = 1, binding = 7) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; -layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; +layout(set = 1, binding = 8) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; -layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer { +layout(set = 1, binding = 9, std430) buffer restrict readonly ClusterBuffer { uint data[]; } cluster_buffer; #ifdef MODE_RENDER_SDF -layout(r16ui, set = 1, binding = 9) uniform restrict writeonly uimage3D albedo_volume_grid; -layout(r32ui, set = 1, binding = 10) uniform restrict writeonly uimage3D emission_grid; -layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_aniso_grid; -layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid; +layout(r16ui, set = 1, binding = 10) uniform restrict writeonly uimage3D albedo_volume_grid; +layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_grid; +layout(r32ui, set = 1, binding = 12) uniform restrict writeonly uimage3D emission_aniso_grid; +layout(r32ui, set = 1, binding = 13) uniform restrict uimage3D geom_facing_grid; //still need to be present for shaders that use it, so remap them to something #define depth_buffer shadow_atlas @@ -319,21 +268,21 @@ layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid; #else -layout(set = 1, binding = 9) uniform texture2D depth_buffer; -layout(set = 1, binding = 10) uniform texture2D color_buffer; +layout(set = 1, binding = 10) uniform texture2D depth_buffer; +layout(set = 1, binding = 11) uniform texture2D color_buffer; #ifdef USE_MULTIVIEW -layout(set = 1, binding = 11) uniform texture2DArray normal_roughness_buffer; -layout(set = 1, binding = 13) uniform texture2DArray ambient_buffer; -layout(set = 1, binding = 14) uniform texture2DArray reflection_buffer; +layout(set = 1, binding = 12) uniform texture2DArray normal_roughness_buffer; +layout(set = 1, binding = 14) uniform texture2DArray ambient_buffer; +layout(set = 1, binding = 15) uniform texture2DArray reflection_buffer; #else // USE_MULTIVIEW -layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer; -layout(set = 1, binding = 13) uniform texture2D ambient_buffer; -layout(set = 1, binding = 14) uniform texture2D reflection_buffer; +layout(set = 1, binding = 12) uniform texture2D normal_roughness_buffer; +layout(set = 1, binding = 14) uniform texture2D ambient_buffer; +layout(set = 1, binding = 15) uniform texture2D reflection_buffer; #endif -layout(set = 1, binding = 12) uniform texture2D ao_buffer; -layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; -layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; +layout(set = 1, binding = 13) uniform texture2D ao_buffer; +layout(set = 1, binding = 16) uniform texture2DArray sdfgi_lightprobe_texture; +layout(set = 1, binding = 17) uniform texture3D sdfgi_occlusion_cascades; struct VoxelGIData { mat4 xform; // 64 - 64 @@ -350,14 +299,14 @@ struct VoxelGIData { float exposure_normalization; // 4 - 112 }; -layout(set = 1, binding = 17, std140) uniform VoxelGIs { +layout(set = 1, binding = 18, std140) uniform VoxelGIs { VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; } voxel_gi_instances; -layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 19) uniform texture3D volumetric_fog_texture; -layout(set = 1, binding = 19) uniform texture2D ssil_buffer; +layout(set = 1, binding = 20) uniform texture2D ssil_buffer; #endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub new file mode 100644 index 0000000000..741da8fe69 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import("env") + +if "RD_GLSL" in env["BUILDERS"]: + # find all include files + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + + # find all shader code(all glsl files excluding our include files) + glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] + + # make sure we recompile shaders if include files change + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"]) + + # compile shaders + for glsl_file in glsl_files: + env.RD_GLSL(glsl_file) diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 5a5ada7231..a109fd4d75 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -101,7 +101,7 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms #ifdef MODE_DUAL_PARABOLOID -layout(location = 8) out highp float dp_clip; +layout(location = 9) out highp float dp_clip; #endif @@ -450,7 +450,7 @@ layout(location = 6) mediump in vec3 binormal_interp; #ifdef MODE_DUAL_PARABOLOID -layout(location = 8) highp in float dp_clip; +layout(location = 9) highp in float dp_clip; #endif @@ -519,7 +519,7 @@ layout(location = 0) out mediump vec4 frag_color; #endif // RENDER DEPTH -#include "scene_forward_aa_inc.glsl" +#include "../scene_forward_aa_inc.glsl" #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) @@ -528,7 +528,7 @@ layout(location = 0) out mediump vec4 frag_color; #define SPECULAR_SCHLICK_GGX #endif -#include "scene_forward_lights_inc.glsl" +#include "../scene_forward_lights_inc.glsl" #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 3a9c52f5bc..5e4999fa0f 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -5,7 +5,8 @@ #extension GL_EXT_multiview : enable #endif -#include "decal_data_inc.glsl" +#include "../decal_data_inc.glsl" +#include "../scene_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) #ifndef NORMAL_USED @@ -32,7 +33,7 @@ draw_call; /* Set 0: Base Pass (never changes) */ -#include "light_data_inc.glsl" +#include "../light_data_inc.glsl" #define SAMPLER_NEAREST_CLAMP 0 #define SAMPLER_LINEAR_CLAMP 1 @@ -127,75 +128,9 @@ global_shader_uniforms; /* Set 1: Render Pass (changes per render pass) */ -struct SceneData { - highp mat4 projection_matrix; - highp mat4 inv_projection_matrix; - highp mat4 inv_view_matrix; - highp mat4 view_matrix; - - // only used for multiview - highp mat4 projection_matrix_view[MAX_VIEWS]; - highp mat4 inv_projection_matrix_view[MAX_VIEWS]; - highp vec4 eye_offset[MAX_VIEWS]; - - highp vec2 viewport_size; - highp vec2 screen_pixel_size; - - // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted. - highp vec4 directional_penumbra_shadow_kernel[32]; - highp vec4 directional_soft_shadow_kernel[32]; - highp vec4 penumbra_shadow_kernel[32]; - highp vec4 soft_shadow_kernel[32]; - - mediump vec4 ambient_light_color_energy; - - mediump float ambient_color_sky_mix; - bool use_ambient_light; - bool use_ambient_cubemap; - bool use_reflection_cubemap; - - mediump mat3 radiance_inverse_xform; - - highp vec2 shadow_atlas_pixel_size; - highp vec2 directional_shadow_pixel_size; - - uint directional_light_count; - mediump float dual_paraboloid_side; - highp float z_far; - highp float z_near; - - bool ssao_enabled; - mediump float ssao_light_affect; - mediump float ssao_ao_affect; - bool roughness_limiter_enabled; - - mediump float roughness_limiter_amount; - mediump float roughness_limiter_limit; - mediump float opaque_prepass_threshold; - uint roughness_limiter_pad; - - bool fog_enabled; - highp float fog_density; - highp float fog_height; - highp float fog_height_density; - - mediump vec3 fog_light_color; - mediump float fog_sun_scatter; - - mediump float fog_aerial_perspective; - bool material_uv2_mode; - - highp float time; - mediump float reflection_multiplier; // one normally, zero when rendering reflections - - bool pancake_shadows; - float emissive_exposure_normalization; - float IBL_exposure_normalization; - uint pad3; -}; - layout(set = 1, binding = 0, std140) uniform SceneDataBlock { SceneData data; + SceneData prev_data; } scene_data_block; diff --git a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl new file mode 100644 index 0000000000..048257e9ef --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl @@ -0,0 +1,69 @@ +// Scene data stores all our 3D rendering globals for a frame such as our matrices +// where this information is independent of the different RD implementations. +// This enables us to use this UBO in our main scene render shaders but also in +// effects that need access to this data. + +struct SceneData { + highp mat4 projection_matrix; + highp mat4 inv_projection_matrix; + highp mat4 inv_view_matrix; + highp mat4 view_matrix; + + // only used for multiview + highp mat4 projection_matrix_view[MAX_VIEWS]; + highp mat4 inv_projection_matrix_view[MAX_VIEWS]; + highp vec4 eye_offset[MAX_VIEWS]; + + highp vec2 viewport_size; + highp vec2 screen_pixel_size; + + // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted. + highp vec4 directional_penumbra_shadow_kernel[32]; + highp vec4 directional_soft_shadow_kernel[32]; + highp vec4 penumbra_shadow_kernel[32]; + highp vec4 soft_shadow_kernel[32]; + + mediump mat3 radiance_inverse_xform; + + mediump vec4 ambient_light_color_energy; + + mediump float ambient_color_sky_mix; + bool use_ambient_light; + bool use_ambient_cubemap; + bool use_reflection_cubemap; + + highp vec2 shadow_atlas_pixel_size; + highp vec2 directional_shadow_pixel_size; + + uint directional_light_count; + mediump float dual_paraboloid_side; + highp float z_far; + highp float z_near; + + bool roughness_limiter_enabled; + mediump float roughness_limiter_amount; + mediump float roughness_limiter_limit; + mediump float opaque_prepass_threshold; + + bool fog_enabled; + highp float fog_density; + highp float fog_height; + highp float fog_height_density; + + mediump vec3 fog_light_color; + mediump float fog_sun_scatter; + + mediump float fog_aerial_perspective; + highp float time; + mediump float reflection_multiplier; // one normally, zero when rendering reflections + bool material_uv2_mode; + + vec2 taa_jitter; + float emissive_exposure_normalization; + float IBL_exposure_normalization; + + bool pancake_shadows; + uint pad1; + uint pad2; + uint pad3; +}; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index 82d609291c..4b34cc74cb 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -34,6 +34,7 @@ #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" +#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" #include "servers/rendering/storage/light_storage.h" #include "servers/rendering/storage/utilities.h" @@ -235,7 +236,7 @@ public: const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); - return light_owner.owns(light->projector); + return TextureStorage::get_singleton()->owns_texture(light->projector); } _FORCE_INLINE_ bool light_is_negative(RID p_light) const { diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index adaf075f80..1975eec7b0 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -35,8 +35,8 @@ #include "servers/rendering/renderer_rd/effects/vrs.h" #include "servers/rendering/renderer_rd/framebuffer_cache_rd.h" #include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h" -#include "servers/rendering/renderer_scene.h" #include "servers/rendering/rendering_device.h" +#include "servers/rendering/rendering_method.h" #include "servers/rendering/storage/render_scene_buffers.h" // These can be retired in due time diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp new file mode 100644 index 0000000000..f925f87cbe --- /dev/null +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp @@ -0,0 +1,246 @@ +/*************************************************************************/ +/* render_scene_data_rd.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "render_scene_data_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/light_storage.h" +#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" +#include "servers/rendering/rendering_server_default.h" + +RID RenderSceneDataRD::create_uniform_buffer() { + return RD::get_singleton()->uniform_buffer_create(sizeof(UBODATA)); +} + +void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers) { + RendererSceneRenderRD *render_scene_render = RendererSceneRenderRD::get_singleton(); + + UBODATA ubo_data; + memset(&ubo_data, 0, sizeof(UBODATA)); + + // just for easy access.. + UBO &ubo = ubo_data.ubo; + UBO &prev_ubo = ubo_data.prev_ubo; + + Projection correction; + correction.set_depth_correction(p_flip_y); + correction.add_jitter_offset(taa_jitter); + Projection projection = correction * cam_projection; + + //store camera into ubo + RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix); + RendererRD::MaterialStorage::store_camera(projection.inverse(), ubo.inv_projection_matrix); + RendererRD::MaterialStorage::store_transform(cam_transform, ubo.inv_view_matrix); + RendererRD::MaterialStorage::store_transform(cam_transform.affine_inverse(), ubo.view_matrix); + + for (uint32_t v = 0; v < view_count; v++) { + projection = correction * view_projection[v]; + RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix_view[v]); + RendererRD::MaterialStorage::store_camera(projection.inverse(), ubo.inv_projection_matrix_view[v]); + + ubo.eye_offset[v][0] = view_eye_offset[v].x; + ubo.eye_offset[v][1] = view_eye_offset[v].y; + ubo.eye_offset[v][2] = view_eye_offset[v].z; + ubo.eye_offset[v][3] = 0.0; + } + + ubo.taa_jitter[0] = taa_jitter.x; + ubo.taa_jitter[1] = taa_jitter.y; + + ubo.z_far = z_far; + ubo.z_near = z_near; + + ubo.pancake_shadows = p_pancake_shadows; + + RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->directional_penumbra_shadow_kernel_get(), ubo.directional_penumbra_shadow_kernel); + RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->directional_soft_shadow_kernel_get(), ubo.directional_soft_shadow_kernel); + RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->penumbra_shadow_kernel_get(), ubo.penumbra_shadow_kernel); + RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->soft_shadow_kernel_get(), ubo.soft_shadow_kernel); + + ubo.viewport_size[0] = p_screen_size.x; + ubo.viewport_size[1] = p_screen_size.y; + + Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); + ubo.screen_pixel_size[0] = screen_pixel_size.x; + ubo.screen_pixel_size[1] = screen_pixel_size.y; + + ubo.shadow_atlas_pixel_size[0] = shadow_atlas_pixel_size.x; + ubo.shadow_atlas_pixel_size[1] = shadow_atlas_pixel_size.y; + + ubo.directional_shadow_pixel_size[0] = directional_shadow_pixel_size.x; + ubo.directional_shadow_pixel_size[1] = directional_shadow_pixel_size.y; + + ubo.time = time; + + ubo.directional_light_count = directional_light_count; + ubo.dual_paraboloid_side = dual_paraboloid_side; + ubo.opaque_prepass_threshold = opaque_prepass_threshold; + ubo.material_uv2_mode = material_uv2_mode; + + ubo.fog_enabled = false; + + if (p_debug_mode == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { + ubo.use_ambient_light = true; + ubo.ambient_light_color_energy[0] = 1; + ubo.ambient_light_color_energy[1] = 1; + ubo.ambient_light_color_energy[2] = 1; + ubo.ambient_light_color_energy[3] = 1.0; + ubo.use_ambient_cubemap = false; + ubo.use_reflection_cubemap = false; + } else if (p_env.is_valid()) { + RS::EnvironmentBG env_bg = render_scene_render->environment_get_background(p_env); + RS::EnvironmentAmbientSource ambient_src = render_scene_render->environment_get_ambient_source(p_env); + + float bg_energy_multiplier = render_scene_render->environment_get_bg_energy_multiplier(p_env); + + ubo.ambient_light_color_energy[3] = bg_energy_multiplier; + + ubo.ambient_color_sky_mix = render_scene_render->environment_get_ambient_sky_contribution(p_env); + + //ambient + if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { + Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : render_scene_render->environment_get_bg_color(p_env); + color = color.srgb_to_linear(); + + ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier; + ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier; + ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier; + ubo.use_ambient_light = true; + ubo.use_ambient_cubemap = false; + } else { + float energy = render_scene_render->environment_get_ambient_light_energy(p_env); + Color color = render_scene_render->environment_get_ambient_light(p_env); + color = color.srgb_to_linear(); + ubo.ambient_light_color_energy[0] = color.r * energy; + ubo.ambient_light_color_energy[1] = color.g * energy; + ubo.ambient_light_color_energy[2] = color.b * energy; + + Basis sky_transform = render_scene_render->environment_get_sky_orientation(p_env); + sky_transform = sky_transform.inverse() * cam_transform.basis; + RendererRD::MaterialStorage::store_transform_3x3(sky_transform, ubo.radiance_inverse_xform); + + ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; + ubo.use_ambient_light = ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; + } + + //specular + RS::EnvironmentReflectionSource ref_src = render_scene_render->environment_get_reflection_source(p_env); + if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { + ubo.use_reflection_cubemap = true; + } else { + ubo.use_reflection_cubemap = false; + } + + ubo.fog_enabled = render_scene_render->environment_get_fog_enabled(p_env); + ubo.fog_density = render_scene_render->environment_get_fog_density(p_env); + ubo.fog_height = render_scene_render->environment_get_fog_height(p_env); + ubo.fog_height_density = render_scene_render->environment_get_fog_height_density(p_env); + ubo.fog_aerial_perspective = render_scene_render->environment_get_fog_aerial_perspective(p_env); + + Color fog_color = render_scene_render->environment_get_fog_light_color(p_env).srgb_to_linear(); + float fog_energy = render_scene_render->environment_get_fog_light_energy(p_env); + + ubo.fog_light_color[0] = fog_color.r * fog_energy; + ubo.fog_light_color[1] = fog_color.g * fog_energy; + ubo.fog_light_color[2] = fog_color.b * fog_energy; + + ubo.fog_sun_scatter = render_scene_render->environment_get_fog_sun_scatter(p_env); + } else { + if (p_reflection_probe_instance.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(p_reflection_probe_instance)) { + ubo.use_ambient_light = false; + } else { + ubo.use_ambient_light = true; + Color clear_color = p_default_bg_color; + clear_color = clear_color.srgb_to_linear(); + ubo.ambient_light_color_energy[0] = clear_color.r; + ubo.ambient_light_color_energy[1] = clear_color.g; + ubo.ambient_light_color_energy[2] = clear_color.b; + ubo.ambient_light_color_energy[3] = 1.0; + } + + ubo.use_ambient_cubemap = false; + ubo.use_reflection_cubemap = false; + } + + if (p_camera_attributes.is_valid()) { + ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes); + ubo.IBL_exposure_normalization = 1.0; + if (p_env.is_valid()) { + RID sky_rid = render_scene_render->environment_get_sky(p_env); + if (sky_rid.is_valid()) { + float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes) * render_scene_render->environment_get_bg_intensity(p_env) / p_luminance_multiplier; + ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, render_scene_render->get_sky()->sky_get_baked_exposure(sky_rid)); + } + } + } else if (emissive_exposure_normalization > 0.0) { + // This branch is triggered when using render_material(). + // Emissive is set outside the function. + ubo.emissive_exposure_normalization = emissive_exposure_normalization; + // IBL isn't used don't set it. + } else { + ubo.emissive_exposure_normalization = 1.0; + ubo.IBL_exposure_normalization = 1.0; + } + + ubo.roughness_limiter_enabled = p_opaque_render_buffers && render_scene_render->screen_space_roughness_limiter_is_active(); + ubo.roughness_limiter_amount = render_scene_render->screen_space_roughness_limiter_get_amount(); + ubo.roughness_limiter_limit = render_scene_render->screen_space_roughness_limiter_get_limit(); + + if (calculate_motion_vectors) { + // Q : Should we make a complete copy or should we define a separate UBO with just the components we need? + memcpy(&prev_ubo, &ubo, sizeof(UBO)); + + Projection prev_correction; + prev_correction.set_depth_correction(true); + prev_correction.add_jitter_offset(prev_taa_jitter); + Projection prev_projection = prev_correction * prev_cam_projection; + + //store camera into ubo + RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix); + RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), prev_ubo.inv_projection_matrix); + RendererRD::MaterialStorage::store_transform(prev_cam_transform, prev_ubo.inv_view_matrix); + RendererRD::MaterialStorage::store_transform(prev_cam_transform.affine_inverse(), prev_ubo.view_matrix); + + for (uint32_t v = 0; v < view_count; v++) { + prev_projection = prev_correction * view_projection[v]; + RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix_view[v]); + RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), prev_ubo.inv_projection_matrix_view[v]); + } + prev_ubo.taa_jitter[0] = prev_taa_jitter.x; + prev_ubo.taa_jitter[1] = prev_taa_jitter.y; + prev_ubo.time -= time_step; + } + + uniform_buffer = p_uniform_buffer; + RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo, RD::BARRIER_MASK_RASTER); +} + +RID RenderSceneDataRD::get_uniform_buffer() { + return uniform_buffer; +} diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h new file mode 100644 index 0000000000..c2dc7d5f4c --- /dev/null +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h @@ -0,0 +1,157 @@ +/*************************************************************************/ +/* render_scene_data_rd.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDER_SCENE_DATA_RD_H +#define RENDER_SCENE_DATA_RD_H + +#include "render_scene_buffers_rd.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_device.h" + +// This is a container for data related to rendering a single frame of a viewport where we load this data into a UBO +// that can be used by the main scene shader but also by various effects. + +class RenderSceneDataRD { +public: + bool calculate_motion_vectors = false; + + Transform3D cam_transform; + Projection cam_projection; + Vector2 taa_jitter; + bool cam_orthogonal = false; + + // For stereo rendering + uint32_t view_count = 1; + Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS]; + Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; + + Transform3D prev_cam_transform; + Projection prev_cam_projection; + Vector2 prev_taa_jitter; + Projection prev_view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; + + float z_near = 0.0; + float z_far = 0.0; + + float lod_distance_multiplier = 0.0; + Plane lod_camera_plane; + float screen_mesh_lod_threshold = 0.0; + + uint32_t directional_light_count = 0; + float dual_paraboloid_side = 0.0; + float opaque_prepass_threshold = 0.0; + bool material_uv2_mode = false; + float emissive_exposure_normalization = 0.0; + + Size2 shadow_atlas_pixel_size; + Size2 directional_shadow_pixel_size; + + float time; + float time_step; + + RID create_uniform_buffer(); + void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers); + RID get_uniform_buffer(); + +private: + RID uniform_buffer; // loaded into this uniform buffer (supplied externally) + + // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code + struct UBO { + float projection_matrix[16]; + float inv_projection_matrix[16]; + float inv_view_matrix[16]; + float view_matrix[16]; + + float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; + float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; + float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4]; + + float viewport_size[2]; + float screen_pixel_size[2]; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; + + float radiance_inverse_xform[12]; + + float ambient_light_color_energy[4]; + + float ambient_color_sky_mix; + uint32_t use_ambient_light; + uint32_t use_ambient_cubemap; + uint32_t use_reflection_cubemap; + + float shadow_atlas_pixel_size[2]; + float directional_shadow_pixel_size[2]; + + uint32_t directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + uint32_t roughness_limiter_enabled; + float roughness_limiter_amount; + float roughness_limiter_limit; + float opaque_prepass_threshold; + + // Fog + uint32_t fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + float fog_light_color[3]; + float fog_sun_scatter; + + float fog_aerial_perspective; + float time; + float reflection_multiplier; + uint32_t material_uv2_mode; + + float taa_jitter[2]; + float emissive_exposure_normalization; // Needed to normalize emissive when using physical units. + float IBL_exposure_normalization; // Adjusts for baked exposure. + + uint32_t pancake_shadows; + uint32_t pad1; + uint32_t pad2; + uint32_t pad3; + }; + + struct UBODATA { + UBO ubo; + UBO prev_ubo; + }; +}; + +#endif // RENDER_SCENE_DATA_RD_H diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 04dedc0646..c2dece8b46 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2910,7 +2910,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } } -void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) { +void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RenderingMethod::RenderInfo *r_render_info) { Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it Scenario *scenario = scenario_owner.get_or_null(p_scenario); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index c799553f87..fedaac99b1 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -39,13 +39,13 @@ #include "core/templates/pass_func.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" -#include "servers/rendering/renderer_scene.h" #include "servers/rendering/renderer_scene_occlusion_cull.h" #include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_method.h" #include "servers/rendering/storage/utilities.h" #include "servers/xr/xr_interface.h" -class RendererSceneCull : public RendererScene { +class RendererSceneCull : public RenderingMethod { public: RendererSceneRender *scene_render = nullptr; @@ -1058,7 +1058,7 @@ public: void _render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr); void render_empty_scene(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_scenario, RID p_shadow_atlas); - void render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RendererScene::RenderInfo *r_render_info = nullptr); + void render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderingMethod::RenderInfo *r_render_info = nullptr); void update_dirty_instances(); void render_particle_colliders(); diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 9aa4108412..34f4980f05 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -34,7 +34,7 @@ #include "core/math/projection.h" #include "core/templates/paged_array.h" #include "servers/rendering/renderer_geometry_instance.h" -#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/rendering_method.h" #include "servers/rendering/storage/environment_storage.h" #include "storage/render_scene_buffers.h" #include "storage/utilities.h" @@ -320,7 +320,7 @@ public: void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect); }; - virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0; + virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0; virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index eacd9bbbc2..2b05e23a96 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -179,7 +179,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { // to compensate for the loss of sharpness. const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias; - p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count()); + p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count); } } } @@ -220,7 +220,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { timestamp_vp_map[rt_id] = p_viewport->self; } - if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") { + if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") { // This is currently needed for GLES to keep the current window being rendered to up to date DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen); } @@ -616,14 +616,7 @@ void RendererViewport::draw_viewports() { if (xr_interface.is_valid()) { // Override our size, make sure it matches our required size and is created as a stereo target Size2 xr_size = xr_interface->get_render_target_size(); - - // Would have been nice if we could call viewport_set_size here, - // but alas that takes our RID and we now have our pointer, - // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change - vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size); - vp->size = xr_size; - uint32_t view_count = xr_interface->get_view_count(); - RSG::texture_storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + _viewport_set_size(vp, xr_size.width, xr_size.height, xr_interface->get_view_count()); // Inform xr interface we're about to render its viewport, if this returns false we don't render visible = xr_interface->pre_draw_viewport(vp->render_target); @@ -686,12 +679,17 @@ void RendererViewport::draw_viewports() { // commit our eyes Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect); if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) { - if (!blit_to_screen_list.has(vp->viewport_to_screen)) { - blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); - } + if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") { + RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size()); + RSG::rasterizer->end_frame(true); + } else { + if (!blit_to_screen_list.has(vp->viewport_to_screen)) { + blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); + } - for (int b = 0; b < blits.size(); b++) { - blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]); + for (int b = 0; b < blits.size(); b++) { + blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]); + } } } } else { @@ -777,7 +775,13 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { } viewport->use_xr = p_use_xr; - _configure_3d_render_buffers(viewport); + + // Re-configure the 3D render buffers when disabling XR. They'll get + // re-configured when enabling XR in draw_viewports(). + if (!p_use_xr) { + viewport->view_count = 1; + _configure_3d_render_buffers(viewport); + } } void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) { @@ -823,34 +827,27 @@ void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_sca _configure_3d_render_buffers(viewport); } -uint32_t RendererViewport::Viewport::get_view_count() { - uint32_t view_count = 1; - - if (use_xr && XRServer::get_singleton() != nullptr) { - Ref<XRInterface> xr_interface; - - xr_interface = XRServer::get_singleton()->get_primary_interface(); - if (xr_interface.is_valid()) { - view_count = xr_interface->get_view_count(); - } - } - - return view_count; -} - void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { ERR_FAIL_COND(p_width < 0 && p_height < 0); Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); + ERR_FAIL_COND_MSG(viewport->use_xr, "Cannot set viewport size when using XR"); - viewport->size = Size2(p_width, p_height); + _viewport_set_size(viewport, p_width, p_height, 1); +} - uint32_t view_count = viewport->get_view_count(); - RSG::texture_storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count); - _configure_3d_render_buffers(viewport); +void RendererViewport::_viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count) { + Size2i new_size(p_width, p_height); + if (p_viewport->size != new_size || p_viewport->view_count != p_view_count) { + p_viewport->size = new_size; + p_viewport->view_count = p_view_count; - viewport->occlusion_buffer_dirty = true; + RSG::texture_storage->render_target_set_size(p_viewport->render_target, p_width, p_height, p_view_count); + _configure_3d_render_buffers(p_viewport); + + p_viewport->occlusion_buffer_dirty = true; + } } void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { @@ -890,7 +887,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ // If using OpenGL we can optimize this operation by rendering directly to system_fbo // instead of rendering to fbo and copying to system_fbo after if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { - RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count()); + RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->view_count); RSG::texture_storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y); } @@ -900,7 +897,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ // if render_direct_to_screen was used, reset size and position if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0); - RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); + RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count); } viewport->viewport_to_screen_rect = Rect2(); @@ -919,7 +916,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool // if disabled, reset render_target size and position if (!p_enable) { RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0); - RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); + RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count); } RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable); @@ -927,7 +924,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) { - RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count()); + RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->view_count); RSG::texture_storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y); } } diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index a123c70372..55058a30b8 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -34,8 +34,8 @@ #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" -#include "servers/rendering/renderer_scene.h" #include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_method.h" #include "servers/rendering_server.h" #include "servers/xr/xr_interface.h" #include "storage/render_scene_buffers.h" @@ -54,6 +54,7 @@ public: Size2i internal_size; Size2i size; + uint32_t view_count; RID camera; RID scenario; @@ -147,9 +148,10 @@ public: HashMap<RID, CanvasData> canvas_map; - RendererScene::RenderInfo render_info; + RenderingMethod::RenderInfo render_info; Viewport() { + view_count = 1; update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE; clear_mode = RS::VIEWPORT_CLEAR_ALWAYS; transparent_bg = false; @@ -176,8 +178,6 @@ public: time_gpu_begin = 0; time_gpu_end = 0; } - - uint32_t get_view_count(); }; HashMap<String, RID> timestamp_vp_map; @@ -196,6 +196,7 @@ public: private: Vector<Viewport *> _sort_active_viewports(); + void _viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count); void _configure_3d_render_buffers(Viewport *p_viewport); void _draw_3d(Viewport *p_viewport); void _draw_viewport(Viewport *p_viewport); diff --git a/servers/rendering/renderer_scene.cpp b/servers/rendering/rendering_method.cpp index b3fdd88626..16a4e35ad3 100644 --- a/servers/rendering/renderer_scene.cpp +++ b/servers/rendering/rendering_method.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* renderer_scene.cpp */ +/* rendering_method.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "renderer_scene.h" +#include "rendering_method.h" -RendererScene::RendererScene() { +RenderingMethod::RenderingMethod() { } -RendererScene::~RendererScene() { +RenderingMethod::~RenderingMethod() { } diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/rendering_method.h index 29c65fcffb..a178b00424 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/rendering_method.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* renderer_scene.h */ +/* rendering_method.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RENDERER_SCENE_H -#define RENDERER_SCENE_H +#ifndef RENDERING_METHOD_H +#define RENDERING_METHOD_H #include "servers/rendering/storage/render_scene_buffers.h" #include "servers/rendering_server.h" #include "servers/xr/xr_interface.h" -class RendererScene { +class RenderingMethod { public: virtual RID camera_allocate() = 0; virtual void camera_initialize(RID p_rid) = 0; @@ -318,8 +318,8 @@ public: virtual bool free(RID p_rid) = 0; - RendererScene(); - virtual ~RendererScene(); + RenderingMethod(); + virtual ~RenderingMethod(); }; -#endif // RENDERER_SCENE_H +#endif // RENDERING_METHOD_H diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index dfe16431bd..5ee29d5e2a 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -550,7 +550,7 @@ public: #undef server_name #undef ServerName //from now on, calls forwarded to this singleton -#define ServerName RendererScene +#define ServerName RenderingMethod #define server_name RSG::scene /* CAMERA API */ @@ -649,7 +649,7 @@ public: #undef server_name #undef ServerName //from now on, calls forwarded to this singleton -#define ServerName RendererScene +#define ServerName RenderingMethod #define server_name RSG::scene FUNC2(directional_shadow_atlas_set_size, int, bool) @@ -739,7 +739,7 @@ public: #undef server_name #undef ServerName -#define ServerName RendererScene +#define ServerName RenderingMethod #define server_name RSG::scene FUNCRIDSPLIT(scenario) diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp index ce7383a03f..ca24042ef9 100644 --- a/servers/rendering/rendering_server_globals.cpp +++ b/servers/rendering/rendering_server_globals.cpp @@ -46,4 +46,4 @@ RendererCompositor *RenderingServerGlobals::rasterizer = nullptr; RendererCanvasCull *RenderingServerGlobals::canvas = nullptr; RendererViewport *RenderingServerGlobals::viewport = nullptr; -RendererScene *RenderingServerGlobals::scene = nullptr; +RenderingMethod *RenderingServerGlobals::scene = nullptr; diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h index 6c4ab5a26e..23f3810ce8 100644 --- a/servers/rendering/rendering_server_globals.h +++ b/servers/rendering/rendering_server_globals.h @@ -35,7 +35,7 @@ #include "servers/rendering/environment/renderer_gi.h" #include "servers/rendering/renderer_canvas_cull.h" #include "servers/rendering/renderer_canvas_render.h" -#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/rendering_method.h" #include "servers/rendering/storage/camera_attributes_storage.h" #include "servers/rendering/storage/light_storage.h" #include "servers/rendering/storage/material_storage.h" @@ -46,7 +46,7 @@ class RendererCanvasCull; class RendererViewport; -class RendererScene; +class RenderingMethod; class RenderingServerGlobals { public: @@ -66,7 +66,7 @@ public: static RendererCanvasCull *canvas; static RendererViewport *viewport; - static RendererScene *scene; + static RenderingMethod *scene; }; #define RSG RenderingServerGlobals diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index cbcfc8fe49..b9df0ec8ac 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2863,18 +2863,12 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048); - GLOBAL_DEF_RST_BASIC("rendering/vulkan/rendering/back_end", 0); - GLOBAL_DEF_RST_BASIC("rendering/vulkan/rendering/back_end.mobile", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/vulkan/rendering/back_end", - PropertyInfo(Variant::INT, - "rendering/vulkan/rendering/back_end", - PROPERTY_HINT_ENUM, "Forward Clustered (Supports Desktop Only),Forward Mobile (Supports Desktop and Mobile)")); // Already defined in RenderingDeviceVulkan::initialize which runs before this code. // We re-define them here just for doctool's sake. Make sure to keep default values in sync. - GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256); - GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128); - GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); - GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64); + GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256); + GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128); + GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64); + GLOBAL_DEF("rendering/rendering_device/descriptor_pools/max_descriptors_per_pool", 64); GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true); GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true); diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h index ae8ca4acde..b6493c5726 100644 --- a/tests/core/math/test_basis.h +++ b/tests/core/math/test_basis.h @@ -47,7 +47,7 @@ enum RotOrder { EulerZYX }; -Vector3 deg2rad(const Vector3 &p_rotation) { +Vector3 deg_to_rad(const Vector3 &p_rotation) { return p_rotation / 180.0 * Math_PI; } @@ -155,7 +155,7 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { // are correct. // Euler to rotation - const Vector3 original_euler = deg2rad(deg_original_euler); + const Vector3 original_euler = deg_to_rad(deg_original_euler); const Basis to_rotation = EulerToBasis(rot_order, original_euler); // Euler from rotation @@ -281,6 +281,59 @@ TEST_CASE("[Stress][Basis] Euler conversions") { } } } + +TEST_CASE("[Basis] Set axis angle") { + Vector3 axis; + real_t angle; + real_t pi = (real_t)Math_PI; + + // Testing the singularity when the angle is 0°. + Basis identity(1, 0, 0, 0, 1, 0, 0, 0, 1); + identity.get_axis_angle(axis, angle); + CHECK(angle == 0); + + // Testing the singularity when the angle is 180°. + Basis singularityPi(-1, 0, 0, 0, 1, 0, 0, 0, -1); + singularityPi.get_axis_angle(axis, angle); + CHECK(Math::is_equal_approx(angle, pi)); + + // Testing reversing the an axis (of an 30° angle). + float cos30deg = Math::cos(Math::deg_to_rad((real_t)30.0)); + Basis z_positive(cos30deg, -0.5, 0, 0.5, cos30deg, 0, 0, 0, 1); + Basis z_negative(cos30deg, 0.5, 0, -0.5, cos30deg, 0, 0, 0, 1); + + z_positive.get_axis_angle(axis, angle); + CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0))); + CHECK(axis == Vector3(0, 0, 1)); + + z_negative.get_axis_angle(axis, angle); + CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0))); + CHECK(axis == Vector3(0, 0, -1)); + + // Testing a rotation of 90° on x-y-z. + Basis x90deg(1, 0, 0, 0, 0, -1, 0, 1, 0); + x90deg.get_axis_angle(axis, angle); + CHECK(Math::is_equal_approx(angle, pi / (real_t)2)); + CHECK(axis == Vector3(1, 0, 0)); + + Basis y90deg(0, 0, 1, 0, 1, 0, -1, 0, 0); + y90deg.get_axis_angle(axis, angle); + CHECK(axis == Vector3(0, 1, 0)); + + Basis z90deg(0, -1, 0, 1, 0, 0, 0, 0, 1); + z90deg.get_axis_angle(axis, angle); + CHECK(axis == Vector3(0, 0, 1)); + + // Regression test: checks that the method returns a small angle (not 0). + Basis tiny(1, 0, 0, 0, 0.9999995, -0.001, 0, 001, 0.9999995); // The min angle possible with float is 0.001rad. + tiny.get_axis_angle(axis, angle); + CHECK(Math::is_equal_approx(angle, (real_t)0.001, (real_t)0.0001)); + + // Regression test: checks that the method returns an angle which is a number (not NaN) + Basis bugNan(1.00000024, 0, 0.000100001693, 0, 1, 0, -0.000100009143, 0, 1.00000024); + bugNan.get_axis_angle(axis, angle); + CHECK(!Math::is_nan(angle)); +} } // namespace TestBasis #endif // TEST_BASIS_H diff --git a/thirdparty/README.md b/thirdparty/README.md index df54f8cf36..b5775db38a 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -214,7 +214,7 @@ Files extracted from upstream source: ## harfbuzz - Upstream: https://github.com/harfbuzz/harfbuzz -- Version: 5.1.0 (f1f2be776bcd994fa9262622e1a7098a066e5cf7, 2022) +- Version: 5.2.0 (4a1d891c6317d2c83e5f3c2607ec5f5ccedffcde, 2022) - License: MIT Files extracted from upstream source: @@ -276,7 +276,7 @@ Files extracted from upstream source: ## libpng - Upstream: http://libpng.org/pub/png/libpng.html -- Version: 1.6.37 (a40189cf881e9f0db80511c382292a5604c3c3d1, 2019) +- Version: 1.6.38 (0a158f3506502dfa23edfc42790dfaed82efba17, 2022) - License: libpng/zlib Files extracted from upstream source: diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh index e52a617c86..eef89a2879 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh @@ -206,7 +206,7 @@ struct Coverage template <typename IterableOut, hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))> - void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const + void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const { switch (u.format) { diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh index 886babd2d1..82fd48dc50 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh @@ -88,7 +88,7 @@ struct CoverageFormat1_3 template <typename IterableOut, hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))> - void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const + void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const { unsigned count = glyphArray.len; for (unsigned i = 0; i < count; i++) diff --git a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh index 4ddb2a73e4..974d094633 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh @@ -140,7 +140,7 @@ struct CoverageFormat2_4 template <typename IterableOut, hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))> - void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const + void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const { for (const auto& range : rangeRecord) { diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh index bfe6b36afd..49e76e7750 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh @@ -58,8 +58,7 @@ struct Anchor return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer)))); } return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer)))); - case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer, - c->plan->layout_variation_idx_map)))); + case 3: return_trace (u.format3.subset (c)); default:return_trace (false); } } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh index d77b4699be..2e30ab33c3 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh @@ -41,24 +41,54 @@ struct AnchorFormat3 *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); } - AnchorFormat3* copy (hb_serialize_context_t *c, - const hb_map_t *layout_variation_idx_map) const + bool subset (hb_subset_context_t *c) const { - TRACE_SERIALIZE (this); - if (!layout_variation_idx_map) return_trace (nullptr); + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + if (unlikely (!c->serializer->embed (format))) return_trace (false); + if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false); + if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); - auto *out = c->embed<AnchorFormat3> (this); - if (unlikely (!out)) return_trace (nullptr); + unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + if (c->plan->layout_variation_idx_delta_map->has (x_varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } - out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); - out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); + unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + if (c->plan->layout_variation_idx_delta_map->has (y_varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } + + if (c->plan->all_axes_pinned) + return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + + if (!c->serializer->embed (xDeviceTable)) return_trace (false); + if (!c->serializer->embed (yDeviceTable)) return_trace (false); + + out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); + out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); return_trace (out); } void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { - (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices); - (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices); + (this+xDeviceTable).collect_variation_indices (c); + (this+yDeviceTable).collect_variation_indices (c); } }; diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh index e16c06729d..408197454f 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh @@ -22,7 +22,8 @@ template<typename Iterator, typename SrcLookup> static void SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, - const hb_map_t *layout_variation_idx_map); + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, + bool all_axes_pinned); } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh index 7a514453ae..a7d489d2a5 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh @@ -9,7 +9,7 @@ struct MarkRecord { friend struct MarkArray; - protected: + public: HBUINT16 klass; /* Class defined for this mark */ Offset16To<Anchor> markAnchor; /* Offset to Anchor table--from diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh index 3cb207281d..ddf7313f94 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -127,6 +127,12 @@ struct PairPosFormat1_3 out->valueFormat[1] = newFormats.second; } + if (c->plan->all_axes_pinned) + { + out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags (); + out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags (); + } + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + hb_zip (this+coverage, pairSet) diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh index a80fe0c226..83b093b988 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -274,13 +274,19 @@ struct PairPosFormat2_4 out->valueFormat1 = newFormats.first; out->valueFormat2 = newFormats.second; + if (c->plan->all_axes_pinned) + { + out->valueFormat1 = out->valueFormat1.drop_device_table_flags (); + out->valueFormat2 = out->valueFormat2.drop_device_table_flags (); + } + for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) { for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map); - valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map); + valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map); + valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_map); } } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh index 4578fbd1d6..aa48d933c3 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh @@ -163,7 +163,7 @@ struct PairSet newFormats, len1, &glyph_map, - c->plan->layout_variation_idx_map + c->plan->layout_variation_idx_delta_map }; const PairValueRecord *record = &firstPairValueRecord; diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh index bd95abde16..3222477764 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh @@ -34,7 +34,7 @@ struct PairValueRecord const ValueFormat *newFormats; unsigned len1; /* valueFormats[0].get_len() */ const hb_map_t *glyph_map; - const hb_map_t *layout_variation_idx_map; + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map; }; bool subset (hb_subset_context_t *c, @@ -50,12 +50,12 @@ struct PairValueRecord closure->valueFormats[0].copy_values (s, closure->newFormats[0], closure->base, &values[0], - closure->layout_variation_idx_map); + closure->layout_variation_idx_delta_map); closure->valueFormats[1].copy_values (s, closure->newFormats[1], closure->base, &values[closure->len1], - closure->layout_variation_idx_map); + closure->layout_variation_idx_delta_map); return_trace (true); } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh index 702f578b3c..6dce3e6343 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh @@ -38,12 +38,16 @@ struct SinglePos void serialize (hb_serialize_context_t *c, const SrcLookup* src, Iterator glyph_val_iter_pairs, - const hb_map_t *layout_variation_idx_map) + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, + bool all_axes_pinned) { if (unlikely (!c->extend_min (u.format))) return; unsigned format = 2; ValueFormat new_format = src->get_value_format (); + if (all_axes_pinned) + new_format = new_format.drop_device_table_flags (); + if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs); @@ -53,13 +57,13 @@ struct SinglePos src, glyph_val_iter_pairs, new_format, - layout_variation_idx_map); + layout_variation_idx_delta_map); return; case 2: u.format2.serialize (c, src, glyph_val_iter_pairs, new_format, - layout_variation_idx_map); + layout_variation_idx_delta_map); return; default:return; } @@ -84,8 +88,9 @@ static void SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, - const hb_map_t *layout_variation_idx_map) -{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); } + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, + bool all_axes_pinned) +{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); } } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh index 7cbdf6dc6c..5a9dd58a63 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -87,7 +87,7 @@ struct SinglePosFormat1 const SrcLookup *src, Iterator it, ValueFormat newFormat, - const hb_map_t *layout_variation_idx_map) + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) { if (unlikely (!c->extend_min (this))) return; if (unlikely (!c->check_assign (valueFormat, @@ -96,7 +96,7 @@ struct SinglePosFormat1 for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second)) { - src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); + src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); // Only serialize the first entry in the iterator, the rest are assumed to // be the same. break; @@ -126,7 +126,7 @@ struct SinglePosFormat1 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); + SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); return_trace (ret); } }; diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh index 518fa9dcb0..8a6e8a42a6 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -99,7 +99,7 @@ struct SinglePosFormat2 const SrcLookup *src, Iterator it, ValueFormat newFormat, - const hb_map_t *layout_variation_idx_map) + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) { auto out = c->extend_min (this); if (unlikely (!out)) return; @@ -109,7 +109,7 @@ struct SinglePosFormat2 + it | hb_map (hb_second) | hb_apply ([&] (hb_array_t<const Value> _) - { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); }) + { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); }) ; auto glyphs = @@ -141,7 +141,7 @@ struct SinglePosFormat2 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); + SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); return_trace (ret); } }; diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh index b29f287bce..26a40f01a3 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh @@ -59,6 +59,24 @@ struct ValueFormat : HBUINT16 unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } unsigned int get_size () const { return get_len () * Value::static_size; } + hb_vector_t<unsigned> get_device_table_indices () const { + unsigned i = 0; + hb_vector_t<unsigned> result; + unsigned format = *this; + + if (format & xPlacement) i++; + if (format & yPlacement) i++; + if (format & xAdvance) i++; + if (format & yAdvance) i++; + + if (format & xPlaDevice) result.push (i++); + if (format & yPlaDevice) result.push (i++); + if (format & xAdvDevice) result.push (i++); + if (format & yAdvDevice) result.push (i++); + + return result; + } + bool apply_value (hb_ot_apply_context_t *c, const void *base, const Value *values, @@ -145,30 +163,50 @@ struct ValueFormat : HBUINT16 unsigned int new_format, const void *base, const Value *values, - const hb_map_t *layout_variation_idx_map) const + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const { unsigned int format = *this; if (!format) return; - if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++); - if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++); - if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++); - if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++); + HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; + if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); + if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); + if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); + if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); - if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & xPlaDevice) + { + add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice); + } + + if (format & yPlaDevice) + { + add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice); + } + + if (format & xAdvDevice) + { + add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice); + } + + if (format & yAdvDevice) + { + add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice); + } } - void copy_value (hb_serialize_context_t *c, - unsigned int new_format, - Flags flag, - Value value) const + HBINT16* copy_value (hb_serialize_context_t *c, + unsigned int new_format, + Flags flag, + Value value) const { // Filter by new format. - if (!(new_format & flag)) return; - c->copy (value); + if (!(new_format & flag)) return nullptr; + return reinterpret_cast<HBINT16 *> (c->copy (value)); } void collect_variation_indices (hb_collect_variation_indices_context_t *c, @@ -183,31 +221,40 @@ struct ValueFormat : HBUINT16 if (format & yAdvance) i++; if (format & xPlaDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yPlaDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::xAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } } + unsigned drop_device_table_flags () const + { + unsigned format = *this; + for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1) + format = format & ~flag; + + return format; + } + private: bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const { @@ -236,9 +283,27 @@ struct ValueFormat : HBUINT16 return *static_cast<const Offset16To<Device> *> (value); } + void add_delta_to_value (HBINT16 *value, + const void *base, + const Value *src_value, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const + { + if (!value) return; + unsigned varidx = (base + get_device (src_value)).get_variation_index (); + hb_pair_t<unsigned, int> *varidx_delta; + if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return; + + *value += hb_second (*varidx_delta); + } + bool copy_device (hb_serialize_context_t *c, const void *base, - const Value *src_value, const hb_map_t *layout_variation_idx_map) const + const Value *src_value, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, + unsigned int new_format, Flags flag) const { + // Filter by new format. + if (!(new_format & flag)) return true; + Value *dst_value = c->copy (*src_value); if (!dst_value) return false; @@ -246,7 +311,7 @@ struct ValueFormat : HBUINT16 *dst_value = 0; c->push (); - if ((base + get_device (src_value)).copy (c, layout_variation_idx_map)) + if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map)) { c->add_link (*dst_value, c->pop_pack ()); return true; diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh index 98f2f5fe7a..852ca3eac5 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh @@ -35,19 +35,17 @@ struct MultipleSubst } } - /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using - * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */ + template<typename Iterator, + hb_requires (hb_is_sorted_iterator (Iterator))> bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> substitute_len_list, - hb_array_t<const HBGlyphID16> substitute_glyphs_list) + Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format = format; switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)); + case 1: return_trace (u.format1.serialize (c, it)); default:return_trace (false); } } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh index 89a04ec3b1..3b4bd11694 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh @@ -71,22 +71,31 @@ struct MultipleSubstFormat1_2 return_trace ((this+sequence[index]).apply (c)); } + template<typename Iterator, + hb_requires (hb_is_sorted_iterator (Iterator))> bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> substitute_len_list, - hb_array_t<const HBGlyphID16> substitute_glyphs_list) + Iterator it) { TRACE_SERIALIZE (this); + auto sequences = + + it + | hb_map (hb_second) + ; + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false); - for (unsigned int i = 0; i < glyphs.length; i++) + + if (unlikely (!sequence.serialize (c, sequences.length))) return_trace (false); + + for (auto& pair : hb_zip (sequences, sequence)) { - unsigned int substitute_len = substitute_len_list[i]; - if (unlikely (!sequence[i] - .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len)))) + if (unlikely (!pair.second + .serialize_serialize (c, pair.first))) return_trace (false); - substitute_glyphs_list += substitute_len; } + return_trace (coverage.serialize_serialize (c, glyphs)); } diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 4b17243d81..13665d7ba1 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -42,6 +42,11 @@ struct SingleSubstFormat1_3 hb_codepoint_t d = deltaGlyphID; hb_codepoint_t mask = get_mask (); + /* Help fuzzer avoid this function as much. */ + unsigned pop = (this+coverage).get_population (); + if (pop >= mask) + return; + hb_set_t intersection; (this+coverage).intersect_set (c->parent_active_glyphs (), intersection); @@ -52,7 +57,7 @@ struct SingleSubstFormat1_3 hb_codepoint_t max_before = intersection.get_max (); hb_codepoint_t min_after = (min_before + d) & mask; hb_codepoint_t max_after = (max_before + d) & mask; - if ((this+coverage).get_population () >= max_before - min_before && + if (pop >= max_before - min_before && ((min_before <= min_after && min_after <= max_before) || (min_before <= max_after && max_after <= max_before))) return; diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh index fb1e90d03e..5416299754 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -41,7 +41,6 @@ struct SingleSubstFormat2_4 | hb_map (hb_second) | hb_sink (c->output) ; - } void closure_lookups (hb_closure_lookups_context_t *c) const {} diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh index 320685b868..d49dcc0e0f 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh @@ -119,19 +119,16 @@ struct SubstLookup : Lookup return_trace (false); } - bool serialize_multiple (hb_serialize_context_t *c, - uint32_t lookup_props, - hb_sorted_array_t<const HBGlyphID16> glyphs, - hb_array_t<const unsigned int> substitute_len_list, - hb_array_t<const HBGlyphID16> substitute_glyphs_list) + template<typename Iterator, + hb_requires (hb_is_sorted_iterator (Iterator))> + bool serialize (hb_serialize_context_t *c, + uint32_t lookup_props, + Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); if (c->push<SubTable> ()->u.multiple. - serialize (c, - glyphs, - substitute_len_list, - substitute_glyphs_list)) + serialize (c, it)) { c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); return_trace (true); diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh index 98c2ee4e73..fc8e309bc9 100644 --- a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh +++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh @@ -105,6 +105,67 @@ struct CompositeGlyphRecord } } + unsigned compile_with_deltas (const contour_point_t &p_delta, + char *out) const + { + const HBINT8 *p = &StructAfter<const HBINT8> (flags); +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) + p += HBGlyphID24::static_size; + else +#endif + p += HBGlyphID16::static_size; + + unsigned len = get_size (); + unsigned len_before_val = (const char *)p - (const char *)this; + if (flags & ARG_1_AND_2_ARE_WORDS) + { + // no overflow, copy and update value with deltas + memcpy (out, this, len); + + const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p); + HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val); + o[0] = px[0] + roundf (p_delta.x); + o[1] = px[1] + roundf (p_delta.y); + } + else + { + int new_x = p[0] + roundf (p_delta.x); + int new_y = p[1] + roundf (p_delta.y); + if (new_x <= 127 && new_x >= -128 && + new_y <= 127 && new_y >= -128) + { + memcpy (out, this, len); + HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val); + o[0] = new_x; + o[1] = new_y; + } + else + { + // int8 overflows after deltas applied + memcpy (out, this, len_before_val); + + //update flags + CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out); + o->flags = flags | ARG_1_AND_2_ARE_WORDS; + out += len_before_val; + + HBINT16 new_value; + new_value = new_x; + memcpy (out, &new_value, HBINT16::static_size); + out += HBINT16::static_size; + + new_value = new_y; + memcpy (out, &new_value, HBINT16::static_size); + out += HBINT16::static_size; + + memcpy (out, p+2, len - len_before_val - 2); + len += 2; + } + } + return len; + } + protected: bool scaled_offsets () const { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } @@ -288,6 +349,63 @@ struct CompositeGlyph return; glyph_chain.set_overlaps_flag (); } + + bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes, + const contour_point_vector_t &deltas, + hb_bytes_t &dest_bytes /* OUT */) + { + if (source_bytes.length <= GlyphHeader::static_size || + header.numberOfContours != -1) + { + dest_bytes = hb_bytes_t (); + return true; + } + + unsigned source_len = source_bytes.length - GlyphHeader::static_size; + + /* try to allocate more memories than source glyph bytes + * in case that there might be an overflow for int8 value + * and we would need to use int16 instead */ + char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char)); + if (unlikely (!o)) return false; + + const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size); + auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c); + + char *p = o; + unsigned i = 0, source_comp_len = 0; + for (const auto &component : it) + { + /* last 4 points in deltas are phantom points and should not be included */ + if (i >= deltas.length - 4) return false; + + unsigned comp_len = component.get_size (); + if (component.is_anchored ()) + { + memcpy (p, &component, comp_len); + p += comp_len; + } + else + { + unsigned new_len = component.compile_with_deltas (deltas[i], p); + p += new_len; + } + i++; + source_comp_len += comp_len; + } + + //copy instructions if any + if (source_len > source_comp_len) + { + unsigned instr_len = source_len - source_comp_len; + memcpy (p, (const char *)c + source_comp_len, instr_len); + p += instr_len; + } + + unsigned len = p - o; + dest_bytes = hb_bytes_t (o, len); + return true; + } }; diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh index 3efe538f37..afcb5dc834 100644 --- a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh +++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh @@ -72,12 +72,117 @@ struct Glyph } } + void update_mtx (const hb_subset_plan_t *plan, + int xMin, int yMax, + const contour_point_vector_t &all_points) const + { + hb_codepoint_t new_gid = 0; + if (!plan->new_gid_for_old_gid (gid, &new_gid)) + return; + + unsigned len = all_points.length; + float leftSideX = all_points[len - 4].x; + float rightSideX = all_points[len - 3].x; + float topSideY = all_points[len - 2].y; + float bottomSideY = all_points[len - 1].y; + + int hori_aw = roundf (rightSideX - leftSideX); + if (hori_aw < 0) hori_aw = 0; + int lsb = roundf (xMin - leftSideX); + plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb)); + + int vert_aw = roundf (topSideY - bottomSideY); + if (vert_aw < 0) vert_aw = 0; + int tsb = roundf (topSideY - yMax); + plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb)); + } + + bool compile_header_bytes (const hb_subset_plan_t *plan, + const contour_point_vector_t &all_points, + hb_bytes_t &dest_bytes /* OUT */) const + { + GlyphHeader *glyph_header = nullptr; + if (all_points.length > 4) + { + glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); + if (unlikely (!glyph_header)) return false; + } + + int xMin, xMax; + xMin = xMax = roundf (all_points[0].x); + + int yMin, yMax; + yMin = yMax = roundf (all_points[0].y); + + for (unsigned i = 1; i < all_points.length - 4; i++) + { + float rounded_x = roundf (all_points[i].x); + float rounded_y = roundf (all_points[i].y); + xMin = hb_min (xMin, rounded_x); + xMax = hb_max (xMax, rounded_x); + yMin = hb_min (yMin, rounded_y); + yMax = hb_max (yMax, rounded_y); + } + + update_mtx (plan, xMin, yMax, all_points); + + /*for empty glyphs: all_points only include phantom points. + *just update metrics and then return */ + if (all_points.length == 4) + return true; + + glyph_header->numberOfContours = header->numberOfContours; + glyph_header->xMin = xMin; + glyph_header->yMin = yMin; + glyph_header->xMax = xMax; + glyph_header->yMax = yMax; + + dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); + return true; + } + + bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, + hb_font_t *font, + const glyf_accelerator_t &glyf, + hb_bytes_t &dest_start, /* IN/OUT */ + hb_bytes_t &dest_end /* OUT */) const + { + contour_point_vector_t all_points, deltas; + get_points (font, glyf, all_points, &deltas, false); + + switch (type) { + case COMPOSITE: + if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, + deltas, + dest_end)) + return false; + break; + case SIMPLE: + if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, + plan->flags & HB_SUBSET_FLAGS_NO_HINTING, + dest_end)) + return false; + break; + default: + /* set empty bytes for empty glyph + * do not use source glyph's pointers */ + dest_start = hb_bytes_t (); + dest_end = hb_bytes_t (); + break; + } + + return compile_header_bytes (plan, all_points, dest_start); + } + + /* Note: Recursively calls itself. * all_points includes phantom points */ template <typename accelerator_t> bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, contour_point_vector_t &all_points /* OUT */, + contour_point_vector_t *deltas = nullptr, /* OUT */ + bool use_my_metrics = true, bool phantom_only = false, unsigned int depth = 0) const { @@ -130,10 +235,28 @@ struct Glyph phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } + if (deltas != nullptr && depth == 0 && type == COMPOSITE) + { + if (unlikely (!deltas->resize (points.length))) return false; + for (unsigned i = 0 ; i < points.length; i++) + deltas->arrayZ[i] = points.arrayZ[i]; + } + #ifndef HB_NO_VAR glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); #endif + // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it + // with child glyphs' points + if (deltas != nullptr && depth == 0 && type == COMPOSITE) + { + for (unsigned i = 0 ; i < points.length; i++) + { + deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x; + deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y; + } + } + switch (type) { case SIMPLE: if (!inplace) @@ -148,11 +271,11 @@ struct Glyph comp_points.reset (); if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) .get_points (font, glyf_accelerator, comp_points, - phantom_only, depth + 1))) + deltas, use_my_metrics, phantom_only, depth + 1))) return false; /* Copy phantom points from component if USE_MY_METRICS flag set */ - if (item.is_use_my_metrics ()) + if (use_my_metrics && item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh index 6df978cf13..b99665d6a0 100644 --- a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh +++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh @@ -206,6 +206,132 @@ struct SimpleGlyph && read_points (p, points_, end, &contour_point_t::y, FLAG_Y_SHORT, FLAG_Y_SAME); } + + static void encode_coord (int value, + uint8_t &flag, + const simple_glyph_flag_t short_flag, + const simple_glyph_flag_t same_flag, + hb_vector_t<uint8_t> &coords /* OUT */) + { + if (value == 0) + { + flag |= same_flag; + } + else if (value >= -255 && value <= 255) + { + flag |= short_flag; + if (value > 0) flag |= same_flag; + else value = -value; + + coords.push ((uint8_t)value); + } + else + { + int16_t val = value; + coords.push (val >> 8); + coords.push (val & 0xff); + } + } + + static void encode_flag (uint8_t &flag, + uint8_t &repeat, + uint8_t &lastflag, + hb_vector_t<uint8_t> &flags /* OUT */) + { + if (flag == lastflag && repeat != 255) + { + repeat = repeat + 1; + if (repeat == 1) + { + flags.push(flag); + } + else + { + unsigned len = flags.length; + flags[len-2] = flag | FLAG_REPEAT; + flags[len-1] = repeat; + } + } + else + { + repeat = 0; + flags.push (flag); + } + lastflag = flag; + } + + bool compile_bytes_with_deltas (const contour_point_vector_t &all_points, + bool no_hinting, + hb_bytes_t &dest_bytes /* OUT */) + { + if (header.numberOfContours == 0 || all_points.length <= 4) + { + dest_bytes = hb_bytes_t (); + return true; + } + //convert absolute values to relative values + unsigned num_points = all_points.length - 4; + hb_vector_t<hb_pair_t<int, int>> deltas; + deltas.resize (num_points); + + for (unsigned i = 0; i < num_points; i++) + { + deltas[i].first = i == 0 ? roundf (all_points[i].x) : roundf (all_points[i].x) - roundf (all_points[i-1].x); + deltas[i].second = i == 0 ? roundf (all_points[i].y) : roundf (all_points[i].y) - roundf (all_points[i-1].y); + } + + hb_vector_t<uint8_t> flags, x_coords, y_coords; + flags.alloc (num_points); + x_coords.alloc (2*num_points); + y_coords.alloc (2*num_points); + + uint8_t lastflag = 0, repeat = 0; + + for (unsigned i = 0; i < num_points; i++) + { + uint8_t flag = all_points[i].flag; + flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE; + + encode_coord (deltas[i].first, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); + encode_coord (deltas[i].second, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); + if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point + encode_flag (flag, repeat, lastflag, flags); + } + + unsigned len_before_instrs = 2 * header.numberOfContours + 2; + unsigned len_instrs = instructions_length (); + unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length; + + if (!no_hinting) + total_len += len_instrs; + + char *p = (char *) hb_calloc (total_len, sizeof (char)); + if (unlikely (!p)) return false; + + const char *src = bytes.arrayZ + GlyphHeader::static_size; + char *cur = p; + memcpy (p, src, len_before_instrs); + + cur += len_before_instrs; + src += len_before_instrs; + + if (!no_hinting) + { + memcpy (cur, src, len_instrs); + cur += len_instrs; + } + + memcpy (cur, flags.arrayZ, flags.length); + cur += flags.length; + + memcpy (cur, x_coords.arrayZ, x_coords.length); + cur += x_coords.length; + + memcpy (cur, y_coords.arrayZ, y_coords.length); + + dest_bytes = hb_bytes_t (p, total_len); + return true; + } }; diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh index 7ae8fe3078..7ddefc5a91 100644 --- a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh +++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh @@ -6,6 +6,9 @@ namespace OT { + +struct glyf_accelerator_t; + namespace glyf_impl { @@ -55,6 +58,17 @@ struct SubsetGlyph return_trace (true); } + bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, + hb_font_t *font, + const glyf_accelerator_t &glyf) + { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); } + + void free_compiled_bytes () + { + dest_start.fini (); + dest_end.fini (); + } + void drop_hints_bytes () { source_glyph.drop_hints_bytes (dest_start, dest_end); } diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh index f51f7a81fc..181c33d06d 100644 --- a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh +++ b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh @@ -16,7 +16,7 @@ template<typename IteratorIn, typename IteratorOut, hb_requires (hb_is_source_of (IteratorIn, unsigned int)), hb_requires (hb_is_sink_of (IteratorOut, unsigned))> static void -_write_loca (IteratorIn it, bool short_offsets, IteratorOut dest) +_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest) { unsigned right_shift = short_offsets ? 1 : 0; unsigned int offset = 0; diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh index bcaf44fc1e..be2cb1d0dc 100644 --- a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh +++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh @@ -24,7 +24,6 @@ namespace OT { */ #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') - struct glyf { friend struct glyf_accelerator_t; @@ -75,6 +74,9 @@ struct glyf hb_vector_t<glyf_impl::SubsetGlyph> glyphs; _populate_subset_glyphs (c->plan, &glyphs); + if (!c->plan->pinned_at_default) + _compile_subset_glyphs_with_deltas (c->plan, &glyphs); + auto padded_offsets = + hb_iter (glyphs) | hb_map (&glyf_impl::SubsetGlyph::padded_size) @@ -93,6 +95,8 @@ struct glyf } + if (!c->plan->pinned_at_default) + _free_compiled_subset_glyphs (&glyphs); if (unlikely (c->serializer->in_error ())) return_trace (false); return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, padded_offsets, @@ -102,6 +106,16 @@ struct glyf void _populate_subset_glyphs (const hb_subset_plan_t *plan, hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const; + + void + _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, + hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const; + + void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const + { + for (auto _ : *glyphs) + _.free_compiled_bytes (); + } protected: UnsizedArrayOf<HBUINT8> @@ -166,7 +180,7 @@ struct glyf_accelerator_t contour_point_vector_t all_points; bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, phantom_only))) return false; if (consumer.is_consuming_contour_points ()) @@ -389,6 +403,30 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, ; } +inline void +glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, + hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const +{ + OT::glyf_accelerator_t glyf (plan->source); + hb_font_t *font = hb_font_create (plan->source); + + hb_vector_t<hb_variation_t> vars; + vars.alloc (plan->user_axes_location->get_population ()); + + for (auto _ : *plan->user_axes_location) + { + hb_variation_t var; + var.tag = _.first; + var.value = _.second; + vars.push (var); + } + + hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); + for (auto& subset_glyph : *glyphs) + const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf); + + hb_font_destroy (font); +} } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/graph/classdef-graph.hh b/thirdparty/harfbuzz/src/graph/classdef-graph.hh new file mode 100644 index 0000000000..0bda76ac2f --- /dev/null +++ b/thirdparty/harfbuzz/src/graph/classdef-graph.hh @@ -0,0 +1,216 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "graph.hh" +#include "../hb-ot-layout-common.hh" + +#ifndef GRAPH_CLASSDEF_GRAPH_HH +#define GRAPH_CLASSDEF_GRAPH_HH + +namespace graph { + +struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes> +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size (); + } +}; + +struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes> +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); + } +}; + +struct ClassDef : public OT::ClassDef +{ + template<typename It> + static bool add_class_def (gsubgpos_graph_context_t& c, + unsigned parent_id, + unsigned link_position, + It glyph_and_class, + unsigned max_size) + { + unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr); + auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id]; + if (!make_class_def (c, glyph_and_class, class_def_prime_id, max_size)) + return false; + + auto* class_def_link = c.graph.vertices_[parent_id].obj.real_links.push (); + class_def_link->width = SmallTypes::size; + class_def_link->objidx = class_def_prime_id; + class_def_link->position = link_position; + class_def_prime_vertex.parents.push (parent_id); + + return true; + } + + template<typename It> + static bool make_class_def (gsubgpos_graph_context_t& c, + It glyph_and_class, + unsigned dest_obj, + unsigned max_size) + { + char* buffer = (char*) hb_calloc (1, max_size); + hb_serialize_context_t serializer (buffer, max_size); + OT::ClassDef_serialize (&serializer, glyph_and_class); + serializer.end_serialize (); + if (serializer.in_error ()) + { + hb_free (buffer); + return false; + } + + hb_bytes_t class_def_copy = serializer.copy_bytes (); + c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + + auto& obj = c.graph.vertices_[dest_obj].obj; + obj.head = (char *) class_def_copy.arrayZ; + obj.tail = obj.head + class_def_copy.length; + + hb_free (buffer); + return true; + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < OT::ClassDef::min_size) return false; + switch (u.format) + { + case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); + case 2: return ((ClassDefFormat2*)this)->sanitize (vertex); +#ifndef HB_NO_BORING_EXPANSION + // Not currently supported + case 3: + case 4: +#endif + default: return false; + } + } +}; + + +struct class_def_size_estimator_t +{ + template<typename It> + class_def_size_estimator_t (It glyph_and_class) + : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class () + { + unsigned last_gid = (unsigned) -1; + for (auto p : + glyph_and_class) + { + unsigned gid = p.first; + unsigned klass = p.second; + + if (last_gid != (unsigned) -1 && gid != last_gid + 1) + gids_consecutive = false; + last_gid = gid; + + hb_set_t* glyphs; + if (glyphs_per_class.has (klass, &glyphs) && glyphs) { + glyphs->add (gid); + continue; + } + + hb_set_t new_glyphs; + new_glyphs.add (gid); + glyphs_per_class.set (klass, std::move (new_glyphs)); + } + + if (in_error ()) return; + + for (unsigned klass : glyphs_per_class.keys ()) + { + if (!klass) continue; // class 0 doesn't get encoded. + + const hb_set_t& glyphs = glyphs_per_class.get (klass); + hb_codepoint_t start = HB_SET_VALUE_INVALID; + hb_codepoint_t end = HB_SET_VALUE_INVALID; + + unsigned count = 0; + while (glyphs.next_range (&start, &end)) + count++; + + num_ranges_per_class.set (klass, count); + } + } + + // Incremental increase in the Coverage and ClassDef table size + // (worst case) if all glyphs associated with 'klass' were added. + unsigned incremental_coverage_size (unsigned klass) const + { + // Coverage takes 2 bytes per glyph worst case, + return 2 * glyphs_per_class.get (klass).get_population (); + } + + // Incremental increase in the Coverage and ClassDef table size + // (worst case) if all glyphs associated with 'klass' were added. + unsigned incremental_class_def_size (unsigned klass) const + { + // ClassDef takes 6 bytes per range + unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass); + if (gids_consecutive) + { + // ClassDef1 takes 2 bytes per glyph, but only can be used + // when gids are consecutive. + return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size); + } + + return class_def_2_size; + } + + bool in_error () + { + if (num_ranges_per_class.in_error ()) return true; + if (glyphs_per_class.in_error ()) return true; + + for (const hb_set_t& s : glyphs_per_class.values ()) + { + if (s.in_error ()) return true; + } + return false; + } + + private: + bool gids_consecutive; + hb_hashmap_t<unsigned, unsigned> num_ranges_per_class; + hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class; +}; + + +} + +#endif // GRAPH_CLASSDEF_GRAPH_HH diff --git a/thirdparty/harfbuzz/src/graph/coverage-graph.hh b/thirdparty/harfbuzz/src/graph/coverage-graph.hh index 1d9fd0eb5b..3c1022f090 100644 --- a/thirdparty/harfbuzz/src/graph/coverage-graph.hh +++ b/thirdparty/harfbuzz/src/graph/coverage-graph.hh @@ -56,6 +56,78 @@ struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes struct Coverage : public OT::Layout::Common::Coverage { + static Coverage* clone_coverage (gsubgpos_graph_context_t& c, + unsigned coverage_id, + unsigned new_parent_id, + unsigned link_position, + unsigned start, unsigned end) + + { + unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); + auto& coverage_v = c.graph.vertices_[coverage_id]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + if (!coverage_table || !coverage_table->sanitize (coverage_v)) + return nullptr; + + auto new_coverage = + + hb_zip (coverage_table->iter (), hb_range ()) + | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) { + return p.second >= start && p.second < end; + }) + | hb_map_retains_sorting (hb_first) + ; + + return add_coverage (c, new_parent_id, link_position, new_coverage, coverage_size); + } + + template<typename It> + static Coverage* add_coverage (gsubgpos_graph_context_t& c, + unsigned parent_id, + unsigned link_position, + It glyphs, + unsigned max_size) + { + unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr); + auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id]; + if (!make_coverage (c, glyphs, coverage_prime_id, max_size)) + return nullptr; + + auto* coverage_link = c.graph.vertices_[parent_id].obj.real_links.push (); + coverage_link->width = SmallTypes::size; + coverage_link->objidx = coverage_prime_id; + coverage_link->position = link_position; + coverage_prime_vertex.parents.push (parent_id); + + return (Coverage*) coverage_prime_vertex.obj.head; + } + + template<typename It> + static bool make_coverage (gsubgpos_graph_context_t& c, + It glyphs, + unsigned dest_obj, + unsigned max_size) + { + char* buffer = (char*) hb_calloc (1, max_size); + hb_serialize_context_t serializer (buffer, max_size); + OT::Layout::Common::Coverage_serialize (&serializer, glyphs); + serializer.end_serialize (); + if (serializer.in_error ()) + { + hb_free (buffer); + return false; + } + + hb_bytes_t coverage_copy = serializer.copy_bytes (); + c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + + auto& obj = c.graph.vertices_[dest_obj].obj; + obj.head = (char *) coverage_copy.arrayZ; + obj.tail = obj.head + coverage_copy.length; + + hb_free (buffer); + return true; + } + bool sanitize (graph_t::vertex_t& vertex) const { int64_t vertex_len = vertex.obj.tail - vertex.obj.head; diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh index b3aef558a2..64878a84a4 100644 --- a/thirdparty/harfbuzz/src/graph/graph.hh +++ b/thirdparty/harfbuzz/src/graph/graph.hh @@ -49,6 +49,51 @@ struct graph_t unsigned end = 0; unsigned priority = 0; + void normalize () + { + obj.real_links.qsort (); + for (auto& l : obj.real_links) + { + for (unsigned i = 0; i < l.width; i++) + { + obj.head[l.position + i] = 0; + } + } + } + + bool equals (const vertex_t& other, + const graph_t& graph, + const graph_t& other_graph, + unsigned depth) const + { + if (!(as_bytes () == other.as_bytes ())) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "vertex [%lu] bytes != [%lu] bytes, depth = %u", + table_size (), + other.table_size (), + depth); + + auto a = as_bytes (); + auto b = other.as_bytes (); + while (a || b) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b); + a++; + b++; + } + return false; + } + + return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth); + } + + hb_bytes_t as_bytes () const + { + return hb_bytes_t (obj.head, table_size ()); + } + friend void swap (vertex_t& a, vertex_t& b) { hb_swap (a.obj, b.obj); @@ -60,6 +105,18 @@ struct graph_t hb_swap (a.priority, b.priority); } + hb_hashmap_t<unsigned, unsigned> + position_to_index_map () const + { + hb_hashmap_t<unsigned, unsigned> result; + + for (const auto& l : obj.real_links) { + result.set (l.position, l.objidx); + } + + return result; + } + bool is_shared () const { return parents.length > 1; @@ -84,7 +141,7 @@ struct graph_t { for (unsigned i = 0; i < obj.real_links.length; i++) { - auto& link = obj.real_links[i]; + auto& link = obj.real_links.arrayZ[i]; if (link.objidx != child_index) continue; @@ -155,6 +212,57 @@ struct graph_t return -table_size; } + + private: + bool links_equal (const hb_vector_t<hb_serialize_context_t::object_t::link_t>& this_links, + const hb_vector_t<hb_serialize_context_t::object_t::link_t>& other_links, + const graph_t& graph, + const graph_t& other_graph, + unsigned depth) const + { + auto a = this_links.iter (); + auto b = other_links.iter (); + + while (a && b) + { + const auto& link_a = *a; + const auto& link_b = *b; + + if (link_a.width != link_b.width || + link_a.is_signed != link_b.is_signed || + link_a.whence != link_b.whence || + link_a.position != link_b.position || + link_a.bias != link_b.bias) + return false; + + if (!graph.vertices_[link_a.objidx].equals ( + other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1)) + return false; + + a++; + b++; + } + + if (bool (a) != bool (b)) + return false; + + return true; + } + }; + + template <typename T> + struct vertex_and_table_t + { + vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr) + {} + + unsigned index; + vertex_t* vertex; + T* table; + + operator bool () { + return table && vertex; + } }; /* @@ -169,7 +277,8 @@ struct graph_t : parents_invalid (true), distance_invalid (true), positions_invalid (true), - successful (true) + successful (true), + buffers () { num_roots_for_space_.push (1); bool removed_nil = false; @@ -201,6 +310,20 @@ struct graph_t ~graph_t () { vertices_.fini (); + for (char* b : buffers) + hb_free (b); + } + + bool operator== (const graph_t& other) const + { + return root ().equals (other.root (), *this, other, 0); + } + + // Sorts links of all objects in a consistent manner and zeroes all offsets. + void normalize () + { + for (auto& v : vertices_.writer ()) + v.normalize (); } bool in_error () const @@ -228,6 +351,27 @@ struct graph_t return vertices_[i].obj; } + void add_buffer (char* buffer) + { + buffers.push (buffer); + } + + /* + * Adds a 16 bit link from parent_id to child_id + */ + template<typename T> + void add_link (T* offset, + unsigned parent_id, + unsigned child_id) + { + auto& v = vertices_[parent_id]; + auto* link = v.obj.real_links.push (); + link->width = 2; + link->objidx = child_id; + link->position = (char*) offset - (char*) v.obj.head; + vertices_[child_id].parents.push (parent_id); + } + /* * Generates a new topological sorting of graph ordered by the shortest * distance to each node if positions are marked as invalid. @@ -345,13 +489,43 @@ struct graph_t } } - unsigned index_for_offset(unsigned node_idx, const void* offset) const + template <typename T, typename ...Ts> + vertex_and_table_t<T> as_table (unsigned parent, const void* offset, Ts... ds) + { + return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...); + } + + template <typename T, typename ...Ts> + vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds) + { + if (index >= vertices_.length) + return vertex_and_table_t<T> (); + + vertex_and_table_t<T> r; + r.vertex = &vertices_[index]; + r.table = (T*) r.vertex->obj.head; + r.index = index; + if (!r.table) + return vertex_and_table_t<T> (); + + if (!r.table->sanitize (*(r.vertex), std::forward<Ts>(ds)...)) + return vertex_and_table_t<T> (); + + return r; + } + + // Finds the object id of the object pointed to by the offset at 'offset' + // within object[node_idx]. + unsigned index_for_offset (unsigned node_idx, const void* offset) const { const auto& node = object (node_idx); if (offset < node.head || offset >= node.tail) return -1; - for (const auto& link : node.real_links) + unsigned length = node.real_links.length; + for (unsigned i = 0; i < length; i++) { + // Use direct access for increased performance, this is a hot method. + const auto& link = node.real_links.arrayZ[i]; if (offset != node.head + link.position) continue; return link.objidx; @@ -360,6 +534,24 @@ struct graph_t return -1; } + // Finds the object id of the object pointed to by the offset at 'offset' + // within object[node_idx]. Ensures that the returned object is safe to mutate. + // That is, if the original child object is shared by parents other than node_idx + // it will be duplicated and the duplicate will be returned instead. + unsigned mutable_index_for_offset (unsigned node_idx, const void* offset) + { + unsigned child_idx = index_for_offset (node_idx, offset); + auto& child = vertices_[child_idx]; + for (unsigned p : child.parents) + { + if (p != node_idx) { + return duplicate (node_idx, child_idx); + } + } + + return child_idx; + } + /* * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s). @@ -1039,6 +1231,7 @@ struct graph_t bool positions_invalid; bool successful; hb_vector_t<unsigned> num_roots_for_space_; + hb_vector_t<char*> buffers; }; } diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc index e0ff6ff85f..b2044426d4 100644 --- a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc +++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc @@ -33,8 +33,7 @@ gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_, : table_tag (table_tag_), graph (graph_), lookup_list_index (0), - lookups (), - buffers () + lookups () { if (table_tag_ != HB_OT_TAG_GPOS && table_tag_ != HB_OT_TAG_GSUB) @@ -53,7 +52,7 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size) if (!buffer) return -1; - buffers.push (buffer); + add_buffer (buffer); return graph.new_node (buffer, buffer + size); } diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh index 49b24198ff..9fe9662e64 100644 --- a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh +++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh @@ -40,22 +40,16 @@ struct gsubgpos_graph_context_t graph_t& graph; unsigned lookup_list_index; hb_hashmap_t<unsigned, graph::Lookup*> lookups; - hb_vector_t<char*> buffers; + HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, graph_t& graph_); - ~gsubgpos_graph_context_t () - { - for (char* b : buffers) - hb_free (b); - } - HB_INTERNAL unsigned create_node (unsigned size); void add_buffer (char* buffer) { - buffers.push (buffer); + graph.add_buffer (buffer); } private: diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh index afa1152c44..a93e7d1c73 100644 --- a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh +++ b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh @@ -29,6 +29,7 @@ #include "../OT/Layout/GSUB/ExtensionSubst.hh" #include "gsubgpos-context.hh" #include "pairpos-graph.hh" +#include "markbasepos-graph.hh" #ifndef GRAPH_GSUBGPOS_GRAPH_HH #define GRAPH_GSUBGPOS_GRAPH_HH @@ -121,10 +122,12 @@ struct Lookup : public OT::Lookup if (c.table_tag != HB_OT_TAG_GPOS) return true; - if (!is_ext && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair) + if (!is_ext && + type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair && + type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) return true; - hb_vector_t<unsigned> all_new_subtables; + hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>> all_new_subtables; for (unsigned i = 0; i < subTable.len; i++) { unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); @@ -133,39 +136,66 @@ struct Lookup : public OT::Lookup ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension = (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) c.graph.object (ext_subtable_index).head; - if (!extension->sanitize (c.graph.vertices_[ext_subtable_index])) + if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index])) continue; subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index); type = extension->get_lookup_type (); - if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair) + if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair + && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) continue; } - PairPos* pairPos = (PairPos*) c.graph.object (subtable_index).head; - if (!pairPos->sanitize (c.graph.vertices_[subtable_index])) continue; - - hb_vector_t<unsigned> new_sub_tables = pairPos->split_subtables (c, subtable_index); + hb_vector_t<unsigned> new_sub_tables; + switch (type) + { + case 2: + new_sub_tables = split_subtable<PairPos> (c, subtable_index); break; + case 4: + new_sub_tables = split_subtable<MarkBasePos> (c, subtable_index); break; + default: + break; + } if (new_sub_tables.in_error ()) return false; - + new_sub_tables.iter() | hb_sink (all_new_subtables); + if (!new_sub_tables) continue; + hb_pair_t<unsigned, hb_vector_t<unsigned>>* entry = all_new_subtables.push (); + entry->first = i; + entry->second = std::move (new_sub_tables); } - if (all_new_subtables) + if (all_new_subtables) { add_sub_tables (c, this_index, type, all_new_subtables); + } return true; } + template<typename T> + hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c, + unsigned objidx) + { + T* sub_table = (T*) c.graph.object (objidx).head; + if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx])) + return hb_vector_t<unsigned> (); + + return sub_table->split_subtables (c, objidx); + } + void add_sub_tables (gsubgpos_graph_context_t& c, unsigned this_index, unsigned type, - hb_vector_t<unsigned>& subtable_indices) + hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids) { bool is_ext = is_extension (c.table_tag); auto& v = c.graph.vertices_[this_index]; + fix_existing_subtable_links (c, this_index, subtable_ids); + + unsigned new_subtable_count = 0; + for (const auto& p : subtable_ids) + new_subtable_count += p.second.length; size_t new_size = v.table_size () - + subtable_indices.length * OT::Offset16::static_size; + + new_subtable_count * OT::Offset16::static_size; char* buffer = (char*) hb_calloc (1, new_size); c.add_buffer (buffer); memcpy (buffer, v.obj.head, v.table_size()); @@ -175,30 +205,61 @@ struct Lookup : public OT::Lookup Lookup* new_lookup = (Lookup*) buffer; - new_lookup->subTable.len = subTable.len + subtable_indices.length; - unsigned offset_index = subTable.len; - for (unsigned subtable_id : subtable_indices) + unsigned shift = 0; + new_lookup->subTable.len = subTable.len + new_subtable_count; + for (const auto& p : subtable_ids) { - if (is_ext) + unsigned offset_index = p.first + shift + 1; + shift += p.second.length; + + for (unsigned subtable_id : p.second) { - unsigned ext_id = create_extension_subtable (c, subtable_id, type); - c.graph.vertices_[subtable_id].parents.push (ext_id); - subtable_id = ext_id; + if (is_ext) + { + unsigned ext_id = create_extension_subtable (c, subtable_id, type); + c.graph.vertices_[subtable_id].parents.push (ext_id); + subtable_id = ext_id; + } + + auto* link = v.obj.real_links.push (); + link->width = 2; + link->objidx = subtable_id; + link->position = (char*) &new_lookup->subTable[offset_index++] - + (char*) new_lookup; + c.graph.vertices_[subtable_id].parents.push (this_index); } - - auto* link = v.obj.real_links.push (); - link->width = 2; - link->objidx = subtable_id; - link->position = (char*) &new_lookup->subTable[offset_index++] - - (char*) new_lookup; - c.graph.vertices_[subtable_id].parents.push (this_index); } + // Repacker sort order depends on link order, which we've messed up so resort it. + v.obj.real_links.qsort (); + // The head location of the lookup has changed, invalidating the lookups map entry // in the context. Update the map. c.lookups.set (this_index, new_lookup); } + void fix_existing_subtable_links (gsubgpos_graph_context_t& c, + unsigned this_index, + hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids) + { + auto& v = c.graph.vertices_[this_index]; + Lookup* lookup = (Lookup*) v.obj.head; + + unsigned shift = 0; + for (const auto& p : subtable_ids) + { + unsigned insert_index = p.first + shift; + unsigned pos_offset = p.second.length * OT::Offset16::static_size; + unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup; + shift += p.second.length; + + for (auto& l : v.obj.all_links_writer ()) + { + if (l.position > insert_offset) l.position += pos_offset; + } + } + } + unsigned create_extension_subtable (gsubgpos_graph_context_t& c, unsigned subtable_index, unsigned type) @@ -281,7 +342,7 @@ struct GSTAR : public OT::GSUBGPOS const auto& r = graph.root (); GSTAR* gstar = (GSTAR*) r.obj.head; - if (!gstar->sanitize (r)) + if (!gstar || !gstar->sanitize (r)) return nullptr; return gstar; @@ -327,17 +388,16 @@ struct GSTAR : public OT::GSUBGPOS hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */) { unsigned lookup_list_idx = get_lookup_list_index (graph); - const LookupList<Types>* lookupList = (const LookupList<Types>*) graph.object (lookup_list_idx).head; - if (!lookupList->sanitize (graph.vertices_[lookup_list_idx])) + if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx])) return; for (unsigned i = 0; i < lookupList->len; i++) { unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i])); Lookup* lookup = (Lookup*) graph.object (lookup_idx).head; - if (!lookup->sanitize (graph.vertices_[lookup_idx])) continue; + if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue; lookups.set (lookup_idx, lookup); } } diff --git a/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh new file mode 100644 index 0000000000..56fa812406 --- /dev/null +++ b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh @@ -0,0 +1,507 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef GRAPH_MARKBASEPOS_GRAPH_HH +#define GRAPH_MARKBASEPOS_GRAPH_HH + +#include "split-helpers.hh" +#include "coverage-graph.hh" +#include "../OT/Layout/GPOS/MarkBasePos.hh" +#include "../OT/Layout/GPOS/PosLookupSubTable.hh" + +namespace graph { + +struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix +{ + bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < AnchorMatrix::min_size) return false; + + return vertex_len >= AnchorMatrix::min_size + + OT::Offset16::static_size * class_count * this->rows; + } + + bool shrink (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned old_class_count, + unsigned new_class_count) + { + if (new_class_count >= old_class_count) return false; + auto& o = c.graph.vertices_[this_index].obj; + unsigned base_count = rows; + o.tail = o.head + + AnchorMatrix::min_size + + OT::Offset16::static_size * base_count * new_class_count; + + // Reposition links into the new indexing scheme. + for (auto& link : o.real_links.writer ()) + { + unsigned index = (link.position - 2) / 2; + unsigned base = index / old_class_count; + unsigned klass = index % old_class_count; + if (klass >= new_class_count) + // should have already been removed + return false; + + unsigned new_index = base * new_class_count + klass; + + link.position = (char*) &(this->matrixZ[new_index]) - (char*) this; + } + + return true; + } + + unsigned clone (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned start, + unsigned end, + unsigned class_count) + { + unsigned base_count = rows; + unsigned new_class_count = end - start; + unsigned size = AnchorMatrix::min_size + + OT::Offset16::static_size * new_class_count * rows; + unsigned prime_id = c.create_node (size); + if (prime_id == (unsigned) -1) return -1; + AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head; + prime->rows = base_count; + + auto& o = c.graph.vertices_[this_index].obj; + int num_links = o.real_links.length; + for (int i = 0; i < num_links; i++) + { + const auto& link = o.real_links[i]; + unsigned old_index = (link.position - 2) / OT::Offset16::static_size; + unsigned klass = old_index % class_count; + if (klass < start || klass >= end) continue; + + unsigned base = old_index / class_count; + unsigned new_klass = klass - start; + unsigned new_index = base * new_class_count + new_klass; + + + unsigned child_idx = link.objidx; + c.graph.add_link (&(prime->matrixZ[new_index]), + prime_id, + child_idx); + + auto& child = c.graph.vertices_[child_idx]; + child.remove_parent (this_index); + + o.real_links.remove (i); + num_links--; + i--; + } + + return prime_id; + } +}; + +struct MarkArray : public OT::Layout::GPOS_impl::MarkArray +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + unsigned min_size = MarkArray::min_size; + if (vertex_len < min_size) return false; + + return vertex_len >= get_size (); + } + + bool shrink (gsubgpos_graph_context_t& c, + const hb_hashmap_t<unsigned, unsigned>& mark_array_links, + unsigned this_index, + unsigned new_class_count) + { + auto& o = c.graph.vertices_[this_index].obj; + for (const auto& link : o.real_links) + c.graph.vertices_[link.objidx].remove_parent (this_index); + o.real_links.reset (); + + unsigned new_index = 0; + for (const auto& record : this->iter ()) + { + unsigned klass = record.klass; + if (klass >= new_class_count) continue; + + (*this)[new_index].klass = klass; + unsigned position = (char*) &record.markAnchor - (char*) this; + unsigned* objidx; + if (!mark_array_links.has (position, &objidx)) + { + new_index++; + continue; + } + + c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx); + new_index++; + } + + this->len = new_index; + o.tail = o.head + MarkArray::min_size + + OT::Layout::GPOS_impl::MarkRecord::static_size * new_index; + return true; + } + + unsigned clone (gsubgpos_graph_context_t& c, + unsigned this_index, + const hb_hashmap_t<unsigned, unsigned>& pos_to_index, + hb_set_t& marks, + unsigned start_class) + { + unsigned size = MarkArray::min_size + + OT::Layout::GPOS_impl::MarkRecord::static_size * + marks.get_population (); + unsigned prime_id = c.create_node (size); + if (prime_id == (unsigned) -1) return -1; + MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head; + prime->len = marks.get_population (); + + + unsigned i = 0; + for (hb_codepoint_t mark : marks) + { + (*prime)[i].klass = (*this)[mark].klass - start_class; + unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this; + unsigned* anchor_index; + if (pos_to_index.has (offset_pos, &anchor_index)) + c.graph.move_child (this_index, + &((*this)[mark].markAnchor), + prime_id, + &((*prime)[i].markAnchor)); + + i++; + } + + return prime_id; + } +}; + +struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes> +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + return vertex_len >= MarkBasePosFormat1::static_size; + } + + hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) + { + hb_set_t visited; + + const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage); + const unsigned base_size = + OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size + + MarkArray::min_size + + AnchorMatrix::min_size + + c.graph.vertices_[base_coverage_id].table_size (); + + hb_vector_t<class_info_t> class_to_info = get_class_info (c, this_index); + + unsigned class_count = classCount; + auto base_array = c.graph.as_table<AnchorMatrix> (this_index, + &baseArray, + class_count); + if (!base_array) return hb_vector_t<unsigned> (); + unsigned base_count = base_array.table->rows; + + unsigned partial_coverage_size = 4; + unsigned accumulated = base_size; + hb_vector_t<unsigned> split_points; + + for (unsigned klass = 0; klass < class_count; klass++) + { + class_info_t& info = class_to_info[klass]; + partial_coverage_size += OT::HBUINT16::static_size * info.marks.get_population (); + unsigned accumulated_delta = + OT::Layout::GPOS_impl::MarkRecord::static_size * info.marks.get_population () + + OT::Offset16::static_size * base_count; + + for (unsigned objidx : info.child_indices) + accumulated_delta += c.graph.find_subgraph_size (objidx, visited); + + accumulated += accumulated_delta; + unsigned total = accumulated + partial_coverage_size; + + if (total >= (1 << 16)) + { + split_points.push (klass); + accumulated = base_size + accumulated_delta; + partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population (); + visited.clear (); // node sharing isn't allowed between splits. + } + } + + + const unsigned mark_array_id = c.graph.index_for_offset (this_index, &markArray); + split_context_t split_context { + c, + this, + this_index, + std::move (class_to_info), + c.graph.vertices_[mark_array_id].position_to_index_map (), + }; + + return actuate_subtable_split<split_context_t> (split_context, split_points); + } + + private: + + struct class_info_t { + hb_set_t marks; + hb_vector_t<unsigned> child_indices; + }; + + struct split_context_t { + gsubgpos_graph_context_t& c; + MarkBasePosFormat1* thiz; + unsigned this_index; + hb_vector_t<class_info_t> class_to_info; + hb_hashmap_t<unsigned, unsigned> mark_array_links; + + hb_set_t marks_for (unsigned start, unsigned end) + { + hb_set_t marks; + for (unsigned klass = start; klass < end; klass++) + { + + class_to_info[klass].marks.iter () + | hb_sink (marks) + ; + } + return marks; + } + + unsigned original_count () + { + return thiz->classCount; + } + + unsigned clone_range (unsigned start, unsigned end) + { + return thiz->clone_range (*this, this->this_index, start, end); + } + + bool shrink (unsigned count) + { + return thiz->shrink (*this, this->this_index, count); + } + }; + + hb_vector_t<class_info_t> get_class_info (gsubgpos_graph_context_t& c, + unsigned this_index) + { + hb_vector_t<class_info_t> class_to_info; + + unsigned class_count= classCount; + class_to_info.resize (class_count); + + auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray); + if (!mark_array) return hb_vector_t<class_info_t> (); + unsigned mark_count = mark_array.table->len; + for (unsigned mark = 0; mark < mark_count; mark++) + { + unsigned klass = (*mark_array.table)[mark].get_class (); + class_to_info[klass].marks.add (mark); + } + + for (const auto& link : mark_array.vertex->obj.real_links) + { + unsigned mark = (link.position - 2) / + OT::Layout::GPOS_impl::MarkRecord::static_size; + unsigned klass = (*mark_array.table)[mark].get_class (); + class_to_info[klass].child_indices.push (link.objidx); + } + + unsigned base_array_id = + c.graph.index_for_offset (this_index, &baseArray); + auto& base_array_v = c.graph.vertices_[base_array_id]; + + for (const auto& link : base_array_v.obj.real_links) + { + unsigned index = (link.position - 2) / OT::Offset16::static_size; + unsigned klass = index % class_count; + class_to_info[klass].child_indices.push (link.objidx); + } + + return class_to_info; + } + + bool shrink (split_context_t& sc, + unsigned this_index, + unsigned count) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Shrinking MarkBasePosFormat1 (%u) to [0, %u).", + this_index, + count); + + unsigned old_count = classCount; + if (count >= old_count) + return true; + + classCount = count; + + auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index, + &markCoverage); + if (!mark_coverage) return false; + hb_set_t marks = sc.marks_for (0, count); + auto new_coverage = + + hb_zip (hb_range (), mark_coverage.table->iter ()) + | hb_filter (marks, hb_first) + | hb_map_retains_sorting (hb_second) + ; + if (!Coverage::make_coverage (sc.c, + new_coverage, + mark_coverage.index, + 4 + 2 * marks.get_population ())) + return false; + + + auto base_array = sc.c.graph.as_table<AnchorMatrix> (this_index, + &baseArray, + old_count); + if (!base_array || !base_array.table->shrink (sc.c, + base_array.index, + old_count, + count)) + return false; + + auto mark_array = sc.c.graph.as_table<MarkArray> (this_index, + &markArray); + if (!mark_array || !mark_array.table->shrink (sc.c, + sc.mark_array_links, + mark_array.index, + count)) + return false; + + return true; + } + + // Create a new MarkBasePos that has all of the data for classes from [start, end). + unsigned clone_range (split_context_t& sc, + unsigned this_index, + unsigned start, unsigned end) const + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end); + + graph_t& graph = sc.c.graph; + unsigned prime_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::static_size; + + unsigned prime_id = sc.c.create_node (prime_size); + if (prime_id == (unsigned) -1) return -1; + + MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head; + prime->format = this->format; + unsigned new_class_count = end - start; + prime->classCount = new_class_count; + + unsigned base_coverage_id = + graph.index_for_offset (sc.this_index, &baseCoverage); + graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id); + graph.duplicate (prime_id, base_coverage_id); + + auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index, + &markCoverage); + if (!mark_coverage) return false; + hb_set_t marks = sc.marks_for (start, end); + auto new_coverage = + + hb_zip (hb_range (), mark_coverage.table->iter ()) + | hb_filter (marks, hb_first) + | hb_map_retains_sorting (hb_second) + ; + if (!Coverage::add_coverage (sc.c, + prime_id, + 2, + + new_coverage, + marks.get_population () * 2 + 4)) + return -1; + + auto mark_array = + graph.as_table <MarkArray> (sc.this_index, &markArray); + if (!mark_array) return -1; + unsigned new_mark_array = + mark_array.table->clone (sc.c, + mark_array.index, + sc.mark_array_links, + marks, + start); + graph.add_link (&(prime->markArray), prime_id, new_mark_array); + + unsigned class_count = classCount; + auto base_array = + graph.as_table<AnchorMatrix> (sc.this_index, &baseArray, class_count); + if (!base_array) return -1; + unsigned new_base_array = + base_array.table->clone (sc.c, + base_array.index, + start, end, this->classCount); + graph.add_link (&(prime->baseArray), prime_id, new_base_array); + + return prime_id; + } +}; + + +struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos +{ + hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, + unsigned this_index) + { + switch (u.format) { + case 1: + return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index); +#ifndef HB_NO_BORING_EXPANSION + case 2: HB_FALLTHROUGH; + // Don't split 24bit PairPos's. +#endif + default: + return hb_vector_t<unsigned> (); + } + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < u.format.get_size ()) return false; + + switch (u.format) { + case 1: + return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex); +#ifndef HB_NO_BORING_EXPANSION + case 2: HB_FALLTHROUGH; +#endif + default: + // We don't handle format 3 and 4 here. + return false; + } + } +}; + + +} + +#endif // GRAPH_MARKBASEPOS_GRAPH_HH diff --git a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh index 3ca4fc701c..976b872329 100644 --- a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh +++ b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh @@ -27,7 +27,9 @@ #ifndef GRAPH_PAIRPOS_GRAPH_HH #define GRAPH_PAIRPOS_GRAPH_HH +#include "split-helpers.hh" #include "coverage-graph.hh" +#include "classdef-graph.hh" #include "../OT/Layout/GPOS/PairPos.hh" #include "../OT/Layout/GPOS/PosLookupSubTable.hh" @@ -51,68 +53,62 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); - const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size - + coverage_size; + const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size; + unsigned partial_coverage_size = 4; unsigned accumulated = base_size; hb_vector_t<unsigned> split_points; for (unsigned i = 0; i < pairSet.len; i++) { unsigned pair_set_index = pair_set_graph_index (c, this_index, i); - accumulated += c.graph.find_subgraph_size (pair_set_index, visited); - accumulated += SmallTypes::size; // for PairSet offset. + unsigned accumulated_delta = + c.graph.find_subgraph_size (pair_set_index, visited) + + SmallTypes::size; // for PairSet offset. + partial_coverage_size += OT::HBUINT16::static_size; - // TODO(garretrieger): don't count the size of the largest pairset against the limit, since - // it will be packed last in the order and does not contribute to - // the 64kb limit. + accumulated += accumulated_delta; + unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size); - if (accumulated > (1 << 16)) + if (total >= (1 << 16)) { split_points.push (i); - accumulated = base_size; - visited.clear (); // Pretend node sharing isn't allowed between splits. + accumulated = base_size + accumulated_delta; + partial_coverage_size = 6; + visited.clear (); // node sharing isn't allowed between splits. } } - return do_split (c, this_index, split_points); + split_context_t split_context { + c, + this, + this_index, + }; + + return actuate_subtable_split<split_context_t> (split_context, split_points); } private: - // Split this PairPos into two or more PairPos's. split_points defines - // the indices (first index to include in the new table) to split at. - // Returns the object id's of the newly created PairPos subtables. - hb_vector_t<unsigned> do_split (gsubgpos_graph_context_t& c, - unsigned this_index, - const hb_vector_t<unsigned> split_points) - { - hb_vector_t<unsigned> new_objects; - if (!split_points) - return new_objects; + struct split_context_t { + gsubgpos_graph_context_t& c; + PairPosFormat1* thiz; + unsigned this_index; - for (unsigned i = 0; i < split_points.length; i++) + unsigned original_count () { - unsigned start = split_points[i]; - unsigned end = (i < split_points.length - 1) ? split_points[i + 1] : pairSet.len; - unsigned id = clone_range (c, this_index, start, end); - - if (id == (unsigned) -1) - { - new_objects.reset (); - new_objects.allocated = -1; // mark error - return new_objects; - } - new_objects.push (id); + return thiz->pairSet.len; } - if (!shrink (c, this_index, split_points[0])) + unsigned clone_range (unsigned start, unsigned end) { - new_objects.reset (); - new_objects.allocated = -1; // mark error + return thiz->clone_range (this->c, this->this_index, start, end); } - return new_objects; - } + bool shrink (unsigned count) + { + return thiz->shrink (this->c, this->this_index, count); + } + }; bool shrink (gsubgpos_graph_context_t& c, unsigned this_index, @@ -129,11 +125,12 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType pairSet.len = count; c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size; - unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + unsigned coverage_id = c.graph.mutable_index_for_offset (this_index, &coverage); unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); auto& coverage_v = c.graph.vertices_[coverage_id]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; - if (!coverage_table->sanitize (coverage_v)) + if (!coverage_table || !coverage_table->sanitize (coverage_v)) return false; auto new_coverage = @@ -144,7 +141,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType | hb_map_retains_sorting (hb_first) ; - return make_coverage (c, new_coverage, coverage_id, coverage_size); + return Coverage::make_coverage (c, new_coverage, coverage_id, coverage_size); } // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive). @@ -178,79 +175,431 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType } unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); - unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); - auto& coverage_v = c.graph.vertices_[coverage_id]; - Coverage* coverage_table = (Coverage*) coverage_v.obj.head; - if (!coverage_table->sanitize (coverage_v)) - return false; + if (!Coverage::clone_coverage (c, + coverage_id, + pair_pos_prime_id, + 2, + start, end)) + return -1; - auto new_coverage = - + hb_zip (coverage_table->iter (), hb_range ()) - | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) { - return p.second >= start && p.second < end; + return pair_pos_prime_id; + } + + + + unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const + { + return c.graph.index_for_offset (this_index, &pairSet[i]); + } +}; + +struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes> +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + size_t vertex_len = vertex.table_size (); + unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size; + if (vertex_len < min_size) return false; + + const unsigned class1_count = class1Count; + return vertex_len >= + min_size + class1_count * get_class1_record_size (); + } + + hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) + { + const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size; + const unsigned class_def_2_size = size_of (c, this_index, &classDef2); + const Coverage* coverage = get_coverage (c, this_index); + const ClassDef* class_def_1 = get_class_def_1 (c, this_index); + auto gid_and_class = + + coverage->iter () + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1->get_class (gid)); }) - | hb_map_retains_sorting (hb_first) ; + class_def_size_estimator_t estimator (gid_and_class); + + const unsigned class1_count = class1Count; + const unsigned class2_count = class2Count; + const unsigned class1_record_size = get_class1_record_size (); - unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr); - auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id]; - if (!make_coverage (c, new_coverage, coverage_prime_id, coverage_size)) + const unsigned value_1_len = valueFormat1.get_len (); + const unsigned value_2_len = valueFormat2.get_len (); + const unsigned total_value_len = value_1_len + value_2_len; + + unsigned accumulated = base_size; + unsigned coverage_size = 4; + unsigned class_def_1_size = 4; + unsigned max_coverage_size = coverage_size; + unsigned max_class_def_1_size = class_def_1_size; + + hb_vector_t<unsigned> split_points; + + hb_hashmap_t<unsigned, unsigned> device_tables = get_all_device_tables (c, this_index); + hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices (); + hb_vector_t<unsigned> format2_device_table_indices = valueFormat2.get_device_table_indices (); + bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices); + + hb_set_t visited; + for (unsigned i = 0; i < class1_count; i++) + { + unsigned accumulated_delta = class1_record_size; + coverage_size += estimator.incremental_coverage_size (i); + class_def_1_size += estimator.incremental_class_def_size (i); + max_coverage_size = hb_max (max_coverage_size, coverage_size); + max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size); + + if (has_device_tables) { + for (unsigned j = 0; j < class2_count; j++) + { + unsigned value1_index = total_value_len * (class2_count * i + j); + unsigned value2_index = value1_index + value_1_len; + accumulated_delta += size_of_value_record_children (c, + device_tables, + format1_device_table_indices, + value1_index, + visited); + accumulated_delta += size_of_value_record_children (c, + device_tables, + format2_device_table_indices, + value2_index, + visited); + } + } + + accumulated += accumulated_delta; + unsigned total = accumulated + + coverage_size + class_def_1_size + class_def_2_size + // The largest object will pack last and can exceed the size limit. + - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size); + if (total >= (1 << 16)) + { + split_points.push (i); + // split does not include i, so add the size for i when we reset the size counters. + accumulated = base_size + accumulated_delta; + coverage_size = 4 + estimator.incremental_coverage_size (i); + class_def_1_size = 4 + estimator.incremental_class_def_size (i); + visited.clear (); // node sharing isn't allowed between splits. + } + } + + split_context_t split_context { + c, + this, + this_index, + class1_record_size, + total_value_len, + value_1_len, + value_2_len, + max_coverage_size, + max_class_def_1_size, + device_tables, + format1_device_table_indices, + format2_device_table_indices + }; + + return actuate_subtable_split<split_context_t> (split_context, split_points); + } + private: + + struct split_context_t + { + gsubgpos_graph_context_t& c; + PairPosFormat2* thiz; + unsigned this_index; + unsigned class1_record_size; + unsigned value_record_len; + unsigned value1_record_len; + unsigned value2_record_len; + unsigned max_coverage_size; + unsigned max_class_def_size; + + const hb_hashmap_t<unsigned, unsigned>& device_tables; + const hb_vector_t<unsigned>& format1_device_table_indices; + const hb_vector_t<unsigned>& format2_device_table_indices; + + unsigned original_count () + { + return thiz->class1Count; + } + + unsigned clone_range (unsigned start, unsigned end) + { + return thiz->clone_range (*this, start, end); + } + + bool shrink (unsigned count) + { + return thiz->shrink (*this, count); + } + }; + + size_t get_class1_record_size () const + { + const size_t class2_count = class2Count; + return + class2_count * (valueFormat1.get_size () + valueFormat2.get_size ()); + } + + unsigned clone_range (split_context_t& split_context, + unsigned start, unsigned end) const + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end); + + graph_t& graph = split_context.c.graph; + + unsigned num_records = end - start; + unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size + + num_records * split_context.class1_record_size; + + unsigned pair_pos_prime_id = split_context.c.create_node (prime_size); + if (pair_pos_prime_id == (unsigned) -1) return -1; + + PairPosFormat2* pair_pos_prime = + (PairPosFormat2*) graph.object (pair_pos_prime_id).head; + pair_pos_prime->format = this->format; + pair_pos_prime->valueFormat1 = this->valueFormat1; + pair_pos_prime->valueFormat2 = this->valueFormat2; + pair_pos_prime->class1Count = num_records; + pair_pos_prime->class2Count = this->class2Count; + clone_class1_records (split_context, + pair_pos_prime_id, + start, + end); + + unsigned coverage_id = + graph.index_for_offset (split_context.this_index, &coverage); + unsigned class_def_1_id = + graph.index_for_offset (split_context.this_index, &classDef1); + auto& coverage_v = graph.vertices_[coverage_id]; + auto& class_def_1_v = graph.vertices_[class_def_1_id]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; + if (!coverage_table + || !coverage_table->sanitize (coverage_v) + || !class_def_1_table + || !class_def_1_table->sanitize (class_def_1_v)) return -1; - auto* coverage_link = c.graph.vertices_[pair_pos_prime_id].obj.real_links.push (); - coverage_link->width = SmallTypes::size; - coverage_link->objidx = coverage_prime_id; - coverage_link->position = 2; - coverage_prime_vertex.parents.push (pair_pos_prime_id); + auto klass_map = + + coverage_table->iter () + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid)); + }) + | hb_filter ([&] (hb_codepoint_t klass) { + return klass >= start && klass < end; + }, hb_second) + | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class) { + // Classes must be from 0...N so subtract start + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid_and_class.first, gid_and_class.second - start); + }) + ; + + if (!Coverage::add_coverage (split_context.c, + pair_pos_prime_id, + 2, + + klass_map | hb_map_retains_sorting (hb_first), + split_context.max_coverage_size)) + return -1; + + // classDef1 + if (!ClassDef::add_class_def (split_context.c, + pair_pos_prime_id, + 8, + + klass_map, + split_context.max_class_def_size)) + return -1; + + // classDef2 + unsigned class_def_2_id = + graph.index_for_offset (split_context.this_index, &classDef2); + auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push (); + class_def_link->width = SmallTypes::size; + class_def_link->objidx = class_def_2_id; + class_def_link->position = 10; + graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id); + graph.duplicate (pair_pos_prime_id, class_def_2_id); return pair_pos_prime_id; } - template<typename It> - bool make_coverage (gsubgpos_graph_context_t& c, - It glyphs, - unsigned dest_obj, - unsigned max_size) const + void clone_class1_records (split_context_t& split_context, + unsigned pair_pos_prime_id, + unsigned start, unsigned end) const { - char* buffer = (char*) hb_calloc (1, max_size); - hb_serialize_context_t serializer (buffer, max_size); - Coverage_serialize (&serializer, glyphs); - serializer.end_serialize (); - if (serializer.in_error ()) + PairPosFormat2* pair_pos_prime = + (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; + + char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size; + unsigned num_records = end - start; + memcpy (&pair_pos_prime->values[0], + start_addr, + num_records * split_context.class1_record_size); + + if (!split_context.format1_device_table_indices + && !split_context.format2_device_table_indices) + // No device tables to move over. + return; + + unsigned class2_count = class2Count; + for (unsigned i = start; i < end; i++) { - hb_free (buffer); - return false; + for (unsigned j = 0; j < class2_count; j++) + { + unsigned value1_index = split_context.value_record_len * (class2_count * i + j); + unsigned value2_index = value1_index + split_context.value1_record_len; + + unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j); + unsigned new_value2_index = new_value1_index + split_context.value1_record_len; + + transfer_device_tables (split_context, + pair_pos_prime_id, + split_context.format1_device_table_indices, + value1_index, + new_value1_index); + + transfer_device_tables (split_context, + pair_pos_prime_id, + split_context.format2_device_table_indices, + value2_index, + new_value2_index); + } } + } - hb_bytes_t coverage_copy = serializer.copy_bytes (); - c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + void transfer_device_tables (split_context_t& split_context, + unsigned pair_pos_prime_id, + const hb_vector_t<unsigned>& device_table_indices, + unsigned old_value_record_index, + unsigned new_value_record_index) const + { + PairPosFormat2* pair_pos_prime = + (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; - auto& obj = c.graph.vertices_[dest_obj].obj; - obj.head = (char *) coverage_copy.arrayZ; - obj.tail = obj.head + coverage_copy.length; + for (unsigned i : device_table_indices) + { + OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i]; + unsigned record_position = ((char*) record) - ((char*) this); + if (!split_context.device_tables.has (record_position)) continue; + + split_context.c.graph.move_child ( + split_context.this_index, + record, + pair_pos_prime_id, + (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]); + } + } - hb_free (buffer); - return true; + bool shrink (split_context_t& split_context, + unsigned count) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Shrinking PairPosFormat2 (%u) to [0, %u).", + split_context.this_index, + count); + unsigned old_count = class1Count; + if (count >= old_count) + return true; + + graph_t& graph = split_context.c.graph; + class1Count = count; + graph.vertices_[split_context.this_index].obj.tail -= + (old_count - count) * split_context.class1_record_size; + + unsigned coverage_id = + graph.mutable_index_for_offset (split_context.this_index, &coverage); + unsigned class_def_1_id = + graph.mutable_index_for_offset (split_context.this_index, &classDef1); + auto& coverage_v = graph.vertices_[coverage_id]; + auto& class_def_1_v = graph.vertices_[class_def_1_id]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; + if (!coverage_table + || !coverage_table->sanitize (coverage_v) + || !class_def_1_table + || !class_def_1_table->sanitize (class_def_1_v)) + return false; + + auto klass_map = + + coverage_table->iter () + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid)); + }) + | hb_filter ([&] (hb_codepoint_t klass) { + return klass < count; + }, hb_second) + ; + + if (!Coverage::make_coverage (split_context.c, + + klass_map | hb_map_retains_sorting (hb_first), + coverage_id, + coverage_v.table_size ())) + return false; + + return ClassDef::make_class_def (split_context.c, + + klass_map, + class_def_1_id, + class_def_1_v.table_size ()); } - unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const + hb_hashmap_t<unsigned, unsigned> + get_all_device_tables (gsubgpos_graph_context_t& c, + unsigned this_index) const { - return c.graph.index_for_offset (this_index, &pairSet[i]); + const auto& v = c.graph.vertices_[this_index]; + return v.position_to_index_map (); } -}; -struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes> -{ - bool sanitize (graph_t::vertex_t& vertex) const + const Coverage* get_coverage (gsubgpos_graph_context_t& c, + unsigned this_index) const { - // TODO(garretrieger): implement me! - return true; + unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + auto& coverage_v = c.graph.vertices_[coverage_id]; + + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + if (!coverage_table || !coverage_table->sanitize (coverage_v)) + return &Null(Coverage); + return coverage_table; } - hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) + const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c, + unsigned this_index) const + { + unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1); + auto& class_def_1_v = c.graph.vertices_[class_def_1_id]; + + ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; + if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v)) + return &Null(ClassDef); + return class_def_1_table; + } + + unsigned size_of_value_record_children (gsubgpos_graph_context_t& c, + const hb_hashmap_t<unsigned, unsigned>& device_tables, + const hb_vector_t<unsigned> device_table_indices, + unsigned value_record_index, + hb_set_t& visited) + { + unsigned size = 0; + for (unsigned i : device_table_indices) + { + OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i]; + unsigned record_position = ((char*) record) - ((char*) this); + unsigned* obj_idx; + if (!device_tables.has (record_position, &obj_idx)) continue; + size += c.graph.find_subgraph_size (*obj_idx, visited); + } + return size; + } + + unsigned size_of (gsubgpos_graph_context_t& c, + unsigned this_index, + const void* offset) const { - // TODO(garretrieger): implement me! - return hb_vector_t<unsigned> (); + const unsigned id = c.graph.index_for_offset (this_index, offset); + return c.graph.vertices_[id].table_size (); } }; diff --git a/thirdparty/harfbuzz/src/graph/split-helpers.hh b/thirdparty/harfbuzz/src/graph/split-helpers.hh new file mode 100644 index 0000000000..61fd7c2d2f --- /dev/null +++ b/thirdparty/harfbuzz/src/graph/split-helpers.hh @@ -0,0 +1,69 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef GRAPH_SPLIT_HELPERS_HH +#define GRAPH_SPLIT_HELPERS_HH + +namespace graph { + +template<typename Context> +HB_INTERNAL +hb_vector_t<unsigned> actuate_subtable_split (Context& split_context, + const hb_vector_t<unsigned>& split_points) +{ + hb_vector_t<unsigned> new_objects; + if (!split_points) + return new_objects; + + for (unsigned i = 0; i < split_points.length; i++) + { + unsigned start = split_points[i]; + unsigned end = (i < split_points.length - 1) + ? split_points[i + 1] + : split_context.original_count (); + unsigned id = split_context.clone_range (start, end); + + if (id == (unsigned) -1) + { + new_objects.reset (); + new_objects.allocated = -1; // mark error + return new_objects; + } + new_objects.push (id); + } + + if (!split_context.shrink (split_points[0])) + { + new_objects.reset (); + new_objects.allocated = -1; // mark error + } + + return new_objects; +} + +} + +#endif // GRAPH_SPLIT_HELPERS_HH diff --git a/thirdparty/harfbuzz/src/graph/test-classdef-graph.cc b/thirdparty/harfbuzz/src/graph/test-classdef-graph.cc new file mode 100644 index 0000000000..55854ff5c2 --- /dev/null +++ b/thirdparty/harfbuzz/src/graph/test-classdef-graph.cc @@ -0,0 +1,119 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "gsubgpos-context.hh" +#include "classdef-graph.hh" + +typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t; +typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t; + + +static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass, + unsigned cov_expected, unsigned class_def_expected) +{ + graph::class_def_size_estimator_t estimator (list.iter ()); + + unsigned result = estimator.incremental_coverage_size (klass); + if (result != cov_expected) + { + printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result); + return false; + } + + result = estimator.incremental_class_def_size (klass); + if (result != class_def_expected) + { + printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result); + return false; + } + + return true; +} + +static void test_class_and_coverage_size_estimates () +{ + gid_and_class_list_t empty = { + }; + assert (incremental_size_is (empty, 0, 0, 0)); + assert (incremental_size_is (empty, 1, 0, 0)); + + gid_and_class_list_t class_zero = { + {5, 0}, + }; + assert (incremental_size_is (class_zero, 0, 2, 0)); + + gid_and_class_list_t consecutive = { + {4, 0}, + {5, 0}, + {6, 1}, + {7, 1}, + {8, 2}, + {9, 2}, + {10, 2}, + {11, 2}, + }; + assert (incremental_size_is (consecutive, 0, 4, 0)); + assert (incremental_size_is (consecutive, 1, 4, 4)); + assert (incremental_size_is (consecutive, 2, 8, 6)); + + gid_and_class_list_t non_consecutive = { + {4, 0}, + {5, 0}, + + {6, 1}, + {7, 1}, + + {9, 2}, + {10, 2}, + {11, 2}, + {12, 2}, + }; + assert (incremental_size_is (non_consecutive, 0, 4, 0)); + assert (incremental_size_is (non_consecutive, 1, 4, 6)); + assert (incremental_size_is (non_consecutive, 2, 8, 6)); + + gid_and_class_list_t multiple_ranges = { + {4, 0}, + {5, 0}, + + {6, 1}, + {7, 1}, + + {9, 1}, + + {11, 1}, + {12, 1}, + {13, 1}, + }; + assert (incremental_size_is (multiple_ranges, 0, 4, 0)); + assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6)); +} + +int +main (int argc, char **argv) +{ + test_class_and_coverage_size_estimates (); +} diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh index 826a901819..5884007c19 100644 --- a/thirdparty/harfbuzz/src/hb-array.hh +++ b/thirdparty/harfbuzz/src/hb-array.hh @@ -342,7 +342,7 @@ struct hb_sorted_array_t : unsigned int i; return bfind (x, &i) ? &this->arrayZ[i] : not_found; } - template <typename T, typename ...Ts> + template <typename T> const Type *bsearch (const T &x, const Type *not_found = nullptr) const { unsigned int i; @@ -389,7 +389,7 @@ struct hb_sorted_array_t : this->length, sizeof (Type), _hb_cmp_method<T, Type, Ts...>, - ds...); + std::forward<Ts> (ds)...); } }; template <typename T> inline hb_sorted_array_t<T> diff --git a/thirdparty/harfbuzz/src/hb-atomic.hh b/thirdparty/harfbuzz/src/hb-atomic.hh index d6dfb0f57a..14c6fb3264 100644 --- a/thirdparty/harfbuzz/src/hb-atomic.hh +++ b/thirdparty/harfbuzz/src/hb-atomic.hh @@ -159,10 +159,13 @@ struct hb_atomic_int_t hb_atomic_int_t () = default; constexpr hb_atomic_int_t (int v) : v (v) {} + hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; } + operator int () const { return get_relaxed (); } + void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } - void set (int v_) { hb_atomic_int_impl_set (&v, v_); } + void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); } int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } - int get () const { return hb_atomic_int_impl_get (&v); } + int get_acquire () const { return hb_atomic_int_impl_get (&v); } int inc () { return hb_atomic_int_impl_add (&v, 1); } int dec () { return hb_atomic_int_impl_add (&v, -1); } @@ -180,11 +183,11 @@ struct hb_atomic_ptr_t void init (T* v_ = nullptr) { set_relaxed (v_); } void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } - T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } + T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } - T * operator -> () const { return get (); } - template <typename C> operator C * () const { return get (); } + T * operator -> () const { return get_acquire (); } + template <typename C> operator C * () const { return get_acquire (); } T *v = nullptr; }; diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh index 4765af67ce..a63887efda 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set.hh @@ -56,7 +56,7 @@ struct hb_bit_set_t { successful = true; population = 0; - last_page_lookup.set_relaxed (0); + last_page_lookup = 0; page_map.init (); pages.init (); } @@ -614,7 +614,7 @@ struct hb_bit_set_t const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (*codepoint); - unsigned int i = last_page_lookup.get_relaxed (); + unsigned int i = last_page_lookup; if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { @@ -632,7 +632,7 @@ struct hb_bit_set_t if (pages_array[current.index].next (codepoint)) { *codepoint += current.major * page_t::PAGE_BITS; - last_page_lookup.set_relaxed (i); + last_page_lookup = i; return true; } i++; @@ -645,11 +645,11 @@ struct hb_bit_set_t if (m != INVALID) { *codepoint = current.major * page_t::PAGE_BITS + m; - last_page_lookup.set_relaxed (i); + last_page_lookup = i; return true; } } - last_page_lookup.set_relaxed (0); + last_page_lookup = 0; *codepoint = INVALID; return false; } @@ -732,7 +732,7 @@ struct hb_bit_set_t { const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (codepoint); - unsigned int i = last_page_lookup.get_relaxed (); + unsigned int i = last_page_lookup; if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST); @@ -773,7 +773,7 @@ struct hb_bit_set_t { const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (codepoint); - unsigned int i = last_page_lookup.get_relaxed (); + unsigned int i = last_page_lookup; if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST); @@ -900,7 +900,7 @@ struct hb_bit_set_t /* The extra page_map length is necessary; can't just rely on vector here, * since the next check would be tricked because a null page also has * major==0, which we can't distinguish from an actualy major==0 page... */ - unsigned i = last_page_lookup.get_relaxed (); + unsigned i = last_page_lookup; if (likely (i < page_map.length)) { auto &cached_page = page_map.arrayZ[i]; @@ -924,7 +924,7 @@ struct hb_bit_set_t page_map[i] = map; } - last_page_lookup.set_relaxed (i); + last_page_lookup = i; return &pages[page_map[i].index]; } const page_t *page_for (hb_codepoint_t g) const @@ -934,7 +934,7 @@ struct hb_bit_set_t /* The extra page_map length is necessary; can't just rely on vector here, * since the next check would be tricked because a null page also has * major==0, which we can't distinguish from an actualy major==0 page... */ - unsigned i = last_page_lookup.get_relaxed (); + unsigned i = last_page_lookup; if (likely (i < page_map.length)) { auto &cached_page = page_map.arrayZ[i]; @@ -946,7 +946,7 @@ struct hb_bit_set_t if (!page_map.bfind (key, &i)) return nullptr; - last_page_lookup.set_relaxed (i); + last_page_lookup = i; return &pages[page_map[i].index]; } page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh index 44c802a00c..87095855d6 100644 --- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh +++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 33 "hb-buffer-deserialize-json.hh" +#line 36 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { 0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, @@ -557,12 +557,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 554 "hb-buffer-deserialize-json.hh" +#line 561 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 557 "hb-buffer-deserialize-json.hh" +#line 566 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -774,7 +774,7 @@ _resume: *end_ptr = p; } break; -#line 735 "hb-buffer-deserialize-json.hh" +#line 778 "hb-buffer-deserialize-json.hh" } _again: diff --git a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh index 8fbcdcc18c..9062610de2 100644 --- a/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh +++ b/thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 33 "hb-buffer-deserialize-text.hh" +#line 36 "hb-buffer-deserialize-text.hh" static const unsigned char _deserialize_text_trans_keys[] = { 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, @@ -509,12 +509,12 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 506 "hb-buffer-deserialize-text.hh" +#line 513 "hb-buffer-deserialize-text.hh" { cs = deserialize_text_start; } -#line 509 "hb-buffer-deserialize-text.hh" +#line 518 "hb-buffer-deserialize-text.hh" { int _slen; int _trans; @@ -894,7 +894,7 @@ _resume: *end_ptr = p; } break; -#line 826 "hb-buffer-deserialize-text.hh" +#line 898 "hb-buffer-deserialize-text.hh" } _again: @@ -1043,7 +1043,7 @@ _again: *end_ptr = p; } break; -#line 953 "hb-buffer-deserialize-text.hh" +#line 1047 "hb-buffer-deserialize-text.hh" } } diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h index c6af759fb9..8c17489835 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.h +++ b/thirdparty/harfbuzz/src/hb-buffer.h @@ -145,7 +145,7 @@ typedef struct hb_glyph_info_t { * @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic, Mongolian, Syriac, etc.), this flag signifies that it is safe to insert a U+0640 TATWEEL - character *before* this cluster for elongation. + character before this cluster for elongation. This flag does not determine the script-specific elongation places, but only when it is safe to do the elongation without diff --git a/thirdparty/harfbuzz/src/hb-cache.hh b/thirdparty/harfbuzz/src/hb-cache.hh index d6b229ed65..897f313fbd 100644 --- a/thirdparty/harfbuzz/src/hb-cache.hh +++ b/thirdparty/harfbuzz/src/hb-cache.hh @@ -32,12 +32,21 @@ /* Implements a lockfree cache for int->int functions. */ -template <unsigned int key_bits=16, unsigned int value_bits=8 + 32 - key_bits, unsigned int cache_bits=8> +template <unsigned int key_bits=16, + unsigned int value_bits=8 + 32 - key_bits, + unsigned int cache_bits=8, + bool thread_safe=true> struct hb_cache_t { + using item_t = typename std::conditional<thread_safe, + hb_atomic_int_t, + typename std::conditional<key_bits + value_bits - cache_bits <= 16, + short, + int>::type + >::type; + static_assert ((key_bits >= cache_bits), ""); - static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), ""); - static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), ""); + static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (item_t)), ""); void init () { clear (); } void fini () {} @@ -45,14 +54,14 @@ struct hb_cache_t void clear () { for (unsigned i = 0; i < ARRAY_LENGTH (values); i++) - values[i].set_relaxed (-1); + values[i] = -1; } bool get (unsigned int key, unsigned int *value) const { unsigned int k = key & ((1u<<cache_bits)-1); - unsigned int v = values[k].get_relaxed (); - if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) || + unsigned int v = values[k]; + if ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t) && v == (unsigned int) -1) || (v >> value_bits) != (key >> cache_bits)) return false; *value = v & ((1u<<value_bits)-1); @@ -65,16 +74,13 @@ struct hb_cache_t return false; /* Overflows */ unsigned int k = key & ((1u<<cache_bits)-1); unsigned int v = ((key>>cache_bits)<<value_bits) | value; - values[k].set_relaxed (v); + values[k] = v; return true; } private: - hb_atomic_int_t values[1u<<cache_bits]; + item_t values[1u<<cache_bits]; }; -typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t; -typedef hb_cache_t<16, 24, 8> hb_advance_cache_t; - #endif /* HB_CACHE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc index e6512872e8..bbb6cd552b 100644 --- a/thirdparty/harfbuzz/src/hb-common.cc +++ b/thirdparty/harfbuzz/src/hb-common.cc @@ -99,7 +99,7 @@ _hb_options_init () } /* This is idempotent and threadsafe. */ - _hb_options.set_relaxed (u.i); + _hb_options = u.i; } diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h index 7c7ad87c7c..e92feb9898 100644 --- a/thirdparty/harfbuzz/src/hb-common.h +++ b/thirdparty/harfbuzz/src/hb-common.h @@ -495,6 +495,8 @@ hb_language_matches (hb_language_t language, * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 + * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0 + * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0 * @HB_SCRIPT_INVALID: No script set * * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding @@ -716,6 +718,12 @@ typedef enum */ HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), + /* + * Since 5.2.0 + */ + HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/ + HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/ + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh index db8ec0e908..5567ddaec3 100644 --- a/thirdparty/harfbuzz/src/hb-config.hh +++ b/thirdparty/harfbuzz/src/hb-config.hh @@ -35,6 +35,9 @@ #include "config.h" #endif +#ifndef HB_BORING_EXPANSION +#define HB_NO_BORING_EXPANSION +#endif #ifdef HB_TINY #define HB_LEAN diff --git a/thirdparty/harfbuzz/src/hb-debug.hh b/thirdparty/harfbuzz/src/hb-debug.hh index 905a46a087..cbe13e5214 100644 --- a/thirdparty/harfbuzz/src/hb-debug.hh +++ b/thirdparty/harfbuzz/src/hb-debug.hh @@ -67,12 +67,12 @@ hb_options () #endif /* Make a local copy, so we can access bitfield threadsafely. */ hb_options_union_t u; - u.i = _hb_options.get_relaxed (); + u.i = _hb_options; if (unlikely (!u.i)) { _hb_options_init (); - u.i = _hb_options.get_relaxed (); + u.i = _hb_options; } return u.opts; diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc index 61adbdd503..2160d6a010 100644 --- a/thirdparty/harfbuzz/src/hb-face.cc +++ b/thirdparty/harfbuzz/src/hb-face.cc @@ -132,7 +132,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, face->user_data = user_data; face->destroy = destroy; - face->num_glyphs.set_relaxed (-1); + face->num_glyphs = -1; face->data.init0 (face); face->table.init0 (face); @@ -479,7 +479,7 @@ hb_face_set_upem (hb_face_t *face, if (hb_object_is_immutable (face)) return; - face->upem.set_relaxed (upem); + face->upem = upem; } /** @@ -514,7 +514,7 @@ hb_face_set_glyph_count (hb_face_t *face, if (hb_object_is_immutable (face)) return; - face->num_glyphs.set_relaxed (glyph_count); + face->num_glyphs = glyph_count; } /** diff --git a/thirdparty/harfbuzz/src/hb-face.hh b/thirdparty/harfbuzz/src/hb-face.hh index 765f272858..12e10d01e0 100644 --- a/thirdparty/harfbuzz/src/hb-face.hh +++ b/thirdparty/harfbuzz/src/hb-face.hh @@ -83,7 +83,7 @@ struct hb_face_t unsigned int get_upem () const { - unsigned int ret = upem.get_relaxed (); + unsigned int ret = upem; if (unlikely (!ret)) { return load_upem (); @@ -93,7 +93,7 @@ struct hb_face_t unsigned int get_num_glyphs () const { - unsigned int ret = num_glyphs.get_relaxed (); + unsigned int ret = num_glyphs; if (unlikely (ret == UINT_MAX)) return load_num_glyphs (); return ret; diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc index ef073475cb..bcc1dd080f 100644 --- a/thirdparty/harfbuzz/src/hb-ft.cc +++ b/thirdparty/harfbuzz/src/hb-ft.cc @@ -80,16 +80,19 @@ */ +using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>; + struct hb_ft_font_t { int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ + bool transform; /* Whether to apply FT_Face's transform. */ mutable hb_mutex_t lock; FT_Face ft_face; mutable unsigned cached_serial; - mutable hb_advance_cache_t advance_cache; + mutable hb_ft_advance_cache_t advance_cache; }; static hb_ft_font_t * @@ -136,6 +139,8 @@ _hb_ft_font_destroy (void *data) /* hb_font changed, update FT_Face. */ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { + hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + float x_mult = 1.f, y_mult = 1.f; if (font->x_scale < 0) x_mult = -x_mult; @@ -173,6 +178,7 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0, 0, (int) roundf (y_mult * (1<<16))}; FT_Set_Transform (ft_face, &matrix, nullptr); + ft_font->transform = true; } #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) @@ -428,13 +434,19 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; + float x_mult; #ifdef HAVE_FT_GET_TRANSFORM - FT_Matrix matrix; - FT_Get_Transform (ft_face, &matrix, nullptr); - float mult = matrix.xx / 65536.f; -#else - float mult = font->x_scale < 0 ? -1 : +1; + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + } + else #endif + { + x_mult = font->x_scale < 0 ? -1 : +1; + } for (unsigned int i = 0; i < count; i++) { @@ -450,7 +462,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, ft_font->advance_cache.set (glyph, v); } - *first_advance = (int) (v * mult + (1<<9)) >> 10; + *first_advance = (int) (v * x_mult + (1<<9)) >> 10; first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); } @@ -466,13 +478,19 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Fixed v; + float y_mult; #ifdef HAVE_FT_GET_TRANSFORM - FT_Matrix matrix; - FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); - float y_mult = matrix.yy / 65536.f; -#else - float y_mult = font->y_scale < 0 ? -1 : +1; + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + } + else #endif + { + y_mult = font->y_scale < 0 ? -1 : +1; + } if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) return 0; @@ -498,15 +516,21 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + float x_mult, y_mult; #ifdef HAVE_FT_GET_TRANSFORM - FT_Matrix matrix; - FT_Get_Transform (ft_face, &matrix, nullptr); - float x_mult = matrix.xx / 65536.f; - float y_mult = matrix.yy / 65536.f; -#else - float x_mult = font->x_scale < 0 ? -1 : +1; - float y_mult = font->y_scale < 0 ? -1 : +1; + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + } + else #endif + { + x_mult = font->x_scale < 0 ? -1 : +1; + y_mult = font->y_scale < 0 ? -1 : +1; + } if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; @@ -553,15 +577,21 @@ hb_ft_get_glyph_extents (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + float x_mult, y_mult; #ifdef HAVE_FT_GET_TRANSFORM - FT_Matrix matrix; - FT_Get_Transform (ft_face, &matrix, nullptr); - float x_mult = matrix.xx / 65536.f; - float y_mult = matrix.yy / 65536.f; -#else - float x_mult = font->x_scale < 0 ? -1 : +1; - float y_mult = font->y_scale < 0 ? -1 : +1; + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + } + else #endif + { + x_mult = font->x_scale < 0 ? -1 : +1; + y_mult = font->y_scale < 0 ? -1 : +1; + } if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; @@ -663,13 +693,19 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + float y_mult; #ifdef HAVE_FT_GET_TRANSFORM - FT_Matrix matrix; - FT_Get_Transform (ft_face, &matrix, nullptr); - float y_mult = matrix.yy / 65536.f; -#else - float y_mult = font->y_scale < 0 ? -1 : +1; + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + } + else #endif + { + y_mult = font->y_scale < 0 ? -1 : +1; + } if (ft_face->units_per_EM != 0) { @@ -1233,13 +1269,14 @@ hb_ft_font_set_funcs (hb_font_t *font) if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); - _hb_ft_hb_font_changed (font, ft_face); ft_face->generic.data = blob; ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; _hb_ft_font_set_funcs (font, ft_face, true); hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); + + _hb_ft_hb_font_changed (font, ft_face); } diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh index ff2a99f5ed..2571f22e15 100644 --- a/thirdparty/harfbuzz/src/hb-machinery.hh +++ b/thirdparty/harfbuzz/src/hb-machinery.hh @@ -176,12 +176,12 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ void init () { instance.set_relaxed (nullptr); } - void fini () { do_destroy (instance.get ()); init (); } + void fini () { do_destroy (instance.get_acquire ()); init (); } void free_instance () { retry: - Stored *p = instance.get (); + Stored *p = instance.get_acquire (); if (unlikely (p && !cmpexch (p, nullptr))) goto retry; do_destroy (p); @@ -203,7 +203,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> Stored * get_stored () const { retry: - Stored *p = this->instance.get (); + Stored *p = this->instance.get_acquire (); if (unlikely (!p)) { if (unlikely (this->is_inert ())) diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh index f6c7a56991..9876c2923c 100644 --- a/thirdparty/harfbuzz/src/hb-object.hh +++ b/thirdparty/harfbuzz/src/hb-object.hh @@ -144,14 +144,14 @@ struct hb_reference_count_t { mutable hb_atomic_int_t ref_count; - void init (int v = 1) { ref_count.set_relaxed (v); } - int get_relaxed () const { return ref_count.get_relaxed (); } + void init (int v = 1) { ref_count = v; } + int get_relaxed () const { return ref_count; } int inc () const { return ref_count.inc (); } int dec () const { return ref_count.dec (); } - void fini () { ref_count.set_relaxed (-0x0000DEAD); } + void fini () { ref_count = -0x0000DEAD; } - bool is_inert () const { return !ref_count.get_relaxed (); } - bool is_valid () const { return ref_count.get_relaxed () > 0; } + bool is_inert () const { return !ref_count; } + bool is_valid () const { return ref_count > 0; } }; @@ -214,15 +214,15 @@ static inline void hb_object_trace (const Type *obj, const char *function) obj ? obj->header.ref_count.get_relaxed () : 0); } -template <typename Type> -static inline Type *hb_object_create () +template <typename Type, typename ...Ts> +static inline Type *hb_object_create (Ts... ds) { Type *obj = (Type *) hb_calloc (1, sizeof (Type)); if (unlikely (!obj)) return obj; - new (obj) Type; + new (obj) Type (std::forward<Ts> (ds)...); hb_object_init (obj); hb_object_trace (obj, HB_FUNC); @@ -233,7 +233,7 @@ template <typename Type> static inline void hb_object_init (Type *obj) { obj->header.ref_count.init (); - obj->header.writable.set_relaxed (true); + obj->header.writable = true; obj->header.user_data.init (); } template <typename Type> @@ -244,12 +244,12 @@ static inline bool hb_object_is_valid (const Type *obj) template <typename Type> static inline bool hb_object_is_immutable (const Type *obj) { - return !obj->header.writable.get_relaxed (); + return !obj->header.writable; } template <typename Type> static inline void hb_object_make_immutable (const Type *obj) { - obj->header.writable.set_relaxed (false); + obj->header.writable = false; } template <typename Type> static inline Type *hb_object_reference (Type *obj) @@ -273,7 +273,8 @@ static inline bool hb_object_destroy (Type *obj) hb_object_fini (obj); - obj->~Type (); + if (!std::is_trivially_destructible<Type>::value) + obj->~Type (); return true; } @@ -281,7 +282,7 @@ template <typename Type> static inline void hb_object_fini (Type *obj) { obj->header.ref_count.fini (); /* Do this before user_data */ - hb_user_data_array_t *user_data = obj->header.user_data.get (); + hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (user_data) { user_data->fini (); @@ -301,7 +302,7 @@ static inline bool hb_object_set_user_data (Type *obj, assert (hb_object_is_valid (obj)); retry: - hb_user_data_array_t *user_data = obj->header.user_data.get (); + hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (unlikely (!user_data)) { user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1); @@ -326,7 +327,7 @@ static inline void *hb_object_get_user_data (Type *obj, if (unlikely (!obj || obj->header.is_inert ())) return nullptr; assert (hb_object_is_valid (obj)); - hb_user_data_array_t *user_data = obj->header.user_data.get (); + hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (!user_data) return nullptr; return user_data->get (key); diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh index 4aa337f78b..17b0296616 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh @@ -1379,7 +1379,7 @@ struct cff1 if (unlikely (!len)) return false; retry: - hb_sorted_vector_t<gname_t> *names = glyph_names.get (); + hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire (); if (unlikely (!names)) { names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1); diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc index 3f13b9994a..c90a65665c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-font.cc +++ b/thirdparty/harfbuzz/src/hb-ot-font.cc @@ -59,13 +59,15 @@ * never need to call these functions directly. **/ +using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; + struct hb_ot_font_t { const hb_ot_face_t *ot_face; /* h_advance caching */ mutable hb_atomic_int_t cached_coords_serial; - mutable hb_atomic_ptr_t<hb_advance_cache_t> advance_cache; + mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache; }; static hb_ot_font_t * @@ -161,14 +163,14 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, bool use_cache = false; #endif - hb_advance_cache_t *cache = nullptr; + hb_ot_font_advance_cache_t *cache = nullptr; if (use_cache) { retry: - cache = ot_font->advance_cache.get (); + cache = ot_font->advance_cache.get_acquire (); if (unlikely (!cache)) { - cache = (hb_advance_cache_t *) hb_malloc (sizeof (hb_advance_cache_t)); + cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t)); if (unlikely (!cache)) { use_cache = false; @@ -181,7 +183,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, hb_free (cache); goto retry; } - ot_font->cached_coords_serial.set (font->serial_coords); + ot_font->cached_coords_serial.set_release (font->serial_coords); } } out: @@ -197,10 +199,10 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, } else { /* Use cache. */ - if (ot_font->cached_coords_serial.get () != (int) font->serial_coords) + if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords) { ot_font->advance_cache->init (); - ot_font->cached_coords_serial.set (font->serial_coords); + ot_font->cached_coords_serial.set_release (font->serial_coords); } for (unsigned int i = 0; i < count; i++) diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh index 50e4b54fde..96a394ba42 100644 --- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh @@ -73,6 +73,8 @@ struct hmtxvmtx return_trace (true); } + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const + { return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; } bool subset_update_header (hb_subset_plan_t *plan, unsigned int num_hmetrics) const @@ -130,14 +132,15 @@ struct hmtxvmtx accelerator_t _mtx (c->plan->source); unsigned num_long_metrics; + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan); { /* Determine num_long_metrics to encode. */ auto& plan = c->plan; + num_long_metrics = plan->num_output_glyphs (); - hb_codepoint_t old_gid = 0; - unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0; + unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && - last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0)) + last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) { num_long_metrics--; } @@ -145,14 +148,18 @@ struct hmtxvmtx auto it = + hb_range (c->plan->num_output_glyphs ()) - | hb_map ([c, &_mtx] (unsigned _) + | hb_map ([c, &_mtx, mtx_map] (unsigned _) { - hb_codepoint_t old_gid; - if (!c->plan->old_gid_for_new_gid (_, &old_gid)) - return hb_pair (0u, 0); - int lsb = 0; - (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); - return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); + if (!mtx_map->has (_)) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (_, &old_gid)) + return hb_pair (0u, 0); + int lsb = 0; + (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); + return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); + } + return mtx_map->get (_); }) ; @@ -330,6 +337,24 @@ struct hmtxvmtx hb_blob_ptr_t<V> var_table; }; + /* get advance: when no variations, call get_advance_without_var_unscaled. + * when there're variations, get advance value from mtx_map in subset_plan*/ + unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map, + unsigned new_gid, + const accelerator_t &_mtx) const + { + if (mtx_map->is_empty () || + (new_gid == 0 && !mtx_map->has (new_gid))) + { + hb_codepoint_t old_gid = 0; + return plan->old_gid_for_new_gid (new_gid, &old_gid) ? + _mtx.get_advance_without_var_unscaled (old_gid) : 0; + } + else + { return mtx_map->get (new_gid).first; } + } + protected: UnsizedArrayOf<LongMetric> longMetricZ; /* Paired advance width and leading diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh index 0532039aad..05916a252c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh @@ -84,10 +84,10 @@ using OT::Layout::MediumTypes; namespace OT { template<typename Iterator> -static inline void ClassDef_serialize (hb_serialize_context_t *c, +static inline bool ClassDef_serialize (hb_serialize_context_t *c, Iterator it); -static void ClassDef_remap_and_serialize ( +static bool ClassDef_remap_and_serialize ( hb_serialize_context_t *c, const hb_set_t &klasses, bool use_class_zero, @@ -186,6 +186,7 @@ struct hb_subset_layout_context_t : unsigned lookup_index_count; }; +struct VariationStore; struct hb_collect_variation_indices_context_t : hb_dispatch_context_t<hb_collect_variation_indices_context_t> { @@ -194,15 +195,27 @@ struct hb_collect_variation_indices_context_t : static return_t default_return_value () { return hb_empty_t (); } hb_set_t *layout_variation_indices; + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map; + hb_font_t *font; + const VariationStore *var_store; const hb_set_t *glyph_set; const hb_map_t *gpos_lookups; + float *store_cache; hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map_, + hb_font_t *font_, + const VariationStore *var_store_, const hb_set_t *glyph_set_, - const hb_map_t *gpos_lookups_) : + const hb_map_t *gpos_lookups_, + float *store_cache_) : layout_variation_indices (layout_variation_indices_), + varidx_delta_map (varidx_delta_map_), + font (font_), + var_store (var_store_), glyph_set (glyph_set_), - gpos_lookups (gpos_lookups_) {} + gpos_lookups (gpos_lookups_), + store_cache (store_cache_) {} }; template<typename OutputArray> @@ -1380,17 +1393,14 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType> */ -static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, +static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c, const hb_set_t &klasses, bool use_class_zero, hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ hb_map_t *klass_map /*IN/OUT*/) { if (!klass_map) - { - ClassDef_serialize (c, glyph_and_klass.iter ()); - return; - } + return ClassDef_serialize (c, glyph_and_klass.iter ()); /* any glyph not assigned a class value falls into Class zero (0), * if any glyph assigned to class 0, remapping must start with 0->0*/ @@ -1413,7 +1423,7 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, } c->propagate_error (glyph_and_klass, klasses); - ClassDef_serialize (c, glyph_and_klass.iter ()); + return ClassDef_serialize (c, glyph_and_klass.iter ()); } /* @@ -1495,11 +1505,12 @@ struct ClassDefFormat1_3 ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) : glyph_map.get_population (); use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; - ClassDef_remap_and_serialize (c->serializer, - orig_klasses, - use_class_zero, - glyph_and_klass, - klass_map); + if (!ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map)) + return_trace (false); return_trace (keep_empty_table || (bool) glyph_and_klass); } @@ -1736,11 +1747,12 @@ struct ClassDefFormat2_4 ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) : glyph_map.get_population (); use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; - ClassDef_remap_and_serialize (c->serializer, - orig_klasses, - use_class_zero, - glyph_and_klass, - klass_map); + if (!ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map)) + return_trace (false); return_trace (keep_empty_table || (bool) glyph_and_klass); } @@ -2124,9 +2136,9 @@ struct ClassDef }; template<typename Iterator> -static inline void ClassDef_serialize (hb_serialize_context_t *c, +static inline bool ClassDef_serialize (hb_serialize_context_t *c, Iterator it) -{ c->start_embed<ClassDef> ()->serialize (c, it); } +{ return (c->start_embed<ClassDef> ()->serialize (c, it)); } /* @@ -2280,16 +2292,16 @@ struct VarData unsigned int count = regionIndices.len; bool is_long = longWords (); unsigned word_count = wordCount (); - unsigned int scount = is_long ? count - word_count : word_count; + unsigned int scount = is_long ? count : word_count; unsigned int lcount = is_long ? word_count : 0; const HBUINT8 *bytes = get_delta_bytes (); - const HBUINT8 *row = bytes + inner * (scount + count); + const HBUINT8 *row = bytes + inner * get_row_size (); float delta = 0.; unsigned int i = 0; - const HBINT16 *lcursor = reinterpret_cast<const HBINT16 *> (row); + const HBINT32 *lcursor = reinterpret_cast<const HBINT32 *> (row); for (; i < lcount; i++) { float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); @@ -2563,7 +2575,7 @@ struct VariationStore bool serialize (hb_serialize_context_t *c, const VariationStore *src, - const hb_array_t <hb_inc_bimap_t> &inner_maps) + const hb_array_t <const hb_inc_bimap_t> &inner_maps) { TRACE_SERIALIZE (this); #ifdef HB_NO_VAR @@ -2618,7 +2630,7 @@ struct VariationStore return_trace (true); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, const hb_array_t<const hb_inc_bimap_t> &inner_maps) const { TRACE_SUBSET (this); #ifdef HB_NO_VAR @@ -2628,22 +2640,7 @@ struct VariationStore VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> (); if (unlikely (!varstore_prime)) return_trace (false); - const hb_set_t *variation_indices = c->plan->layout_variation_indices; - if (variation_indices->is_empty ()) return_trace (false); - - hb_vector_t<hb_inc_bimap_t> inner_maps; - inner_maps.resize ((unsigned) dataSets.len); - - for (unsigned idx : c->plan->layout_variation_indices->iter ()) - { - uint16_t major = idx >> 16; - uint16_t minor = idx & 0xFFFF; - - if (major >= inner_maps.length) - return_trace (false); - inner_maps[major].add (minor); - } - varstore_prime->serialize (c->serializer, this, inner_maps.as_array ()); + varstore_prime->serialize (c->serializer, this, inner_maps); return_trace ( !c->serializer->in_error() @@ -3169,28 +3166,36 @@ struct VariationDevice VariationStore::cache_t *store_cache = nullptr) const { return font->em_scalef_y (get_delta (font, store, store_cache)); } - VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const + VariationDevice* copy (hb_serialize_context_t *c, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const { TRACE_SERIALIZE (this); + if (!layout_variation_idx_delta_map) return_trace (nullptr); auto snap = c->snapshot (); auto *out = c->embed (this); if (unlikely (!out)) return_trace (nullptr); - if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out); /* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */ - if (!layout_variation_idx_map->has (varIdx)) + if (!layout_variation_idx_delta_map->has (varIdx)) { c->revert (snap); return_trace (nullptr); } - unsigned new_idx = layout_variation_idx_map->get (varIdx); + unsigned new_idx = hb_first (layout_variation_idx_delta_map->get (varIdx)); out->varIdx = new_idx; return_trace (out); } - void record_variation_index (hb_set_t *layout_variation_indices) const + void collect_variation_index (hb_collect_variation_indices_context_t *c) const { - layout_variation_indices->add (varIdx); + c->layout_variation_indices->add (varIdx); + int delta = 0; + if (c->font && c->var_store) + delta = roundf (get_delta (c->font, *c->var_store, c->store_cache)); + + /* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap + * varidx later*/ + c->varidx_delta_map->set (varIdx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta)); } bool sanitize (hb_sanitize_context_t *c) const @@ -3283,7 +3288,8 @@ struct Device } } - Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const + Device* copy (hb_serialize_context_t *c, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map=nullptr) const { TRACE_SERIALIZE (this); switch (u.b.format) { @@ -3295,14 +3301,14 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: - return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_map))); + return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_delta_map))); #endif default: return_trace (nullptr); } } - void collect_variation_indices (hb_set_t *layout_variation_indices) const + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { switch (u.b.format) { #ifndef HB_NO_HINTING @@ -3313,7 +3319,7 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: - u.variation.record_variation_index (layout_variation_indices); + u.variation.collect_variation_index (c); return; #endif default: @@ -3321,6 +3327,18 @@ struct Device } } + unsigned get_variation_index () const + { + switch (u.b.format) { +#ifndef HB_NO_VAR + case 0x8000: + return u.variation.varIdx; +#endif + default: + return HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + } + } + protected: union { DeviceHeader b; diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh index 5bc26d9182..22925fdfa9 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh @@ -200,15 +200,34 @@ struct CaretValueFormat3 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); + auto *out = c->serializer->start_embed (*this); if (unlikely (!out)) return_trace (false); + if (!c->serializer->embed (caretValueFormat)) return_trace (false); + if (!c->serializer->embed (coordinate)) return_trace (false); + + unsigned varidx = (this+deviceTable).get_variation_index (); + if (c->plan->layout_variation_idx_delta_map->has (varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } + + if (c->plan->all_axes_pinned) + return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + + if (!c->serializer->embed (deviceTable)) + return_trace (false); return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), - hb_serialize_context_t::Head, c->plan->layout_variation_idx_map)); + hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map)); } - void collect_variation_indices (hb_set_t *layout_variation_indices) const - { (this+deviceTable).collect_variation_indices (layout_variation_indices); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { (this+deviceTable).collect_variation_indices (c); } bool sanitize (hb_sanitize_context_t *c) const { @@ -255,14 +274,14 @@ struct CaretValue } } - void collect_variation_indices (hb_set_t *layout_variation_indices) const + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { switch (u.format) { case 1: case 2: return; case 3: - u.format3.collect_variation_indices (layout_variation_indices); + u.format3.collect_variation_indices (c); return; default: return; } @@ -329,7 +348,7 @@ struct LigGlyph void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { for (const Offset16To<CaretValue>& offset : carets.iter ()) - (this+offset).collect_variation_indices (c->layout_variation_indices); + (this+offset).collect_variation_indices (c); } bool sanitize (hb_sanitize_context_t *c) const @@ -586,7 +605,10 @@ struct GDEFVersion1_2 bool subset_varstore = false; if (version.to_int () >= 0x00010003u) { - subset_varstore = out->varStore.serialize_subset (c, varStore, this); + if (c->plan->all_axes_pinned) + out->varStore = 0; + else + subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); } if (subset_varstore) @@ -846,7 +868,7 @@ struct GDEF { get_lig_caret_list ().collect_variation_indices (c); } void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, - hb_map_t *layout_variation_idx_map /* OUT */) const + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const { if (!has_var_store ()) return; if (layout_variation_indices->is_empty ()) return; @@ -864,7 +886,11 @@ struct GDEF } unsigned new_idx = (new_major << 16) + new_minor; - layout_variation_idx_map->set (idx, new_idx); + if (!layout_variation_idx_delta_map->has (idx)) + continue; + int delta = hb_second (layout_variation_idx_delta_map->get (idx)); + + layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta)); ++new_minor; last_major = major; } diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh index c77ec12fbe..c15a42b0f1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh @@ -4261,6 +4261,7 @@ struct GSUBGPOS } void prune_langsys (const hb_map_t *duplicate_feature_map, + const hb_set_t *layout_scripts, hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map, hb_set_t *new_feature_indexes /* OUT */) const { @@ -4269,6 +4270,8 @@ struct GSUBGPOS unsigned count = get_script_count (); for (unsigned script_index = 0; script_index < count; script_index++) { + const Tag& tag = get_script_tag (script_index); + if (!layout_scripts->has (tag)) continue; const Script& s = get_script (script_index); s.prune_langsys (&c, script_index); } diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc index f9c0daa486..44e57987b7 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.cc +++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc @@ -601,9 +601,13 @@ hb_ot_layout_table_select_script (hb_face_t *face, * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table * * Fetches a list of all feature tags in the given face's GSUB or GPOS table. + * Note that there might be duplicate feature tags, belonging to different + * script/language-system pairs of the table. * * Return value: Total number of feature tags. * + * Since: 0.6.0 + * **/ unsigned int hb_ot_layout_table_get_feature_tags (hb_face_t *face, @@ -629,6 +633,9 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face, * or GPOS table. * * Return value: `true` if the feature is found, `false` otherwise + * + * Since: 0.6.0 + * **/ bool hb_ot_layout_table_find_feature (hb_face_t *face, @@ -668,6 +675,8 @@ hb_ot_layout_table_find_feature (hb_face_t *face, * * Return value: Total number of language tags. * + * Since: 0.6.0 + * **/ unsigned int hb_ot_layout_script_get_language_tags (hb_face_t *face, @@ -778,6 +787,8 @@ hb_ot_layout_script_select_language (hb_face_t *face, * * Return value: `true` if the feature is found, `false` otherwise * + * Since: 0.6.0 + * **/ hb_bool_t hb_ot_layout_language_get_required_feature_index (hb_face_t *face, @@ -846,6 +857,9 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face, * returned will begin at the offset provided. * * Return value: Total number of features. + * + * Since: 0.6.0 + * **/ unsigned int hb_ot_layout_language_get_feature_indexes (hb_face_t *face, @@ -879,6 +893,9 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face, * returned will begin at the offset provided. * * Return value: Total number of feature tags. + * + * Since: 0.6.0 + * **/ unsigned int hb_ot_layout_language_get_feature_tags (hb_face_t *face, @@ -919,6 +936,8 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face, * * Return value: `true` if the feature is found, `false` otherwise * + * Since: 0.6.0 + * **/ hb_bool_t hb_ot_layout_language_find_feature (hb_face_t *face, @@ -1167,9 +1186,12 @@ script_collect_features (hb_collect_features_context_t *c, * hb_ot_layout_collect_features: * @face: #hb_face_t to work upon * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS - * @scripts: The array of scripts to collect features for - * @languages: The array of languages to collect features for - * @features: The array of features to collect + * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect features for, + * terminated by %HB_TAG_NONE + * @languages: (nullable) (array zero-terminated=1): The array of languages to collect features for, + * terminated by %HB_TAG_NONE + * @features: (nullable) (array zero-terminated=1): The array of features to collect, + * terminated by %HB_TAG_NONE * @feature_indexes: (out): The array of feature indexes found for the query * * Fetches a list of all feature indexes in the specified face's GSUB table @@ -1216,9 +1238,12 @@ hb_ot_layout_collect_features (hb_face_t *face, * hb_ot_layout_collect_lookups: * @face: #hb_face_t to work upon * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS - * @scripts: The array of scripts to collect lookups for - * @languages: The array of languages to collect lookups for - * @features: The array of features to collect lookups for + * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect lookups for, + * terminated by %HB_TAG_NONE + * @languages: (nullable) (array zero-terminated=1): The array of languages to collect lookups for, + * terminated by %HB_TAG_NONE + * @features: (nullable) (array zero-terminated=1): The array of features to collect lookups for, + * terminated by %HB_TAG_NONE * @lookup_indexes: (out): The array of lookup indexes found for the query * * Fetches a list of all feature-lookup indexes in the specified face's GSUB @@ -1316,6 +1341,8 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, * * Return value: `true` if feature variations were found, `false` otherwise. * + * Since: 1.4.0 + * **/ hb_bool_t hb_ot_layout_table_find_feature_variations (hb_face_t *face, @@ -1347,6 +1374,8 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face, * * Return value: Total number of lookups. * + * Since: 1.4.0 + * **/ unsigned int hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, @@ -1379,6 +1408,8 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, * * Return value: `true` if data found, `false` otherwise * + * Since: 0.6.0 + * **/ hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face) @@ -2297,11 +2328,6 @@ struct hb_get_glyph_alternates_dispatch_t : static return_t default_return_value () { return 0; } bool stop_sublookup_iteration (return_t r) const { return r; } - hb_face_t *face; - - hb_get_glyph_alternates_dispatch_t (hb_face_t *face) : - face (face) {} - private: template <typename T, typename ...Ts> auto _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN @@ -2340,7 +2366,7 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face, unsigned *alternate_count /* IN/OUT. May be NULL. */, hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) { - hb_get_glyph_alternates_dispatch_t c (face); + hb_get_glyph_alternates_dispatch_t c; const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index); auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs); if (!ret && alternate_count) *alternate_count = 0; diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh index 3473afef54..c6e8fad6fc 100644 --- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh @@ -166,6 +166,47 @@ struct OS2 } } + float map_wdth_to_widthclass(float width) const + { + if (width < 50) return 1.0f; + if (width > 200) return 9.0f; + + float ratio = (width - 50) / 12.5f; + int a = (int) floorf (ratio); + int b = (int) ceilf (ratio); + + /* follow this maping: + * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass + */ + if (b <= 6) // 50-125 + { + if (a == b) return a + 1.0f; + } + else if (b == 7) // no mapping for 137.5 + { + a = 6; + b = 8; + } + else if (b == 8) + { + if (a == b) return 8.0f; // 150 + a = 6; + } + else + { + if (a == b && a == 12) return 9.0f; //200 + b = 12; + a = 8; + } + + float va = 50 + a * 12.5f; + float vb = 50 + b * 12.5f; + + float ret = a + (width - va) / (vb - va); + if (a <= 6) ret += 1.0f; + return ret; + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -183,6 +224,26 @@ struct OS2 _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange); + if (c->plan->user_axes_location->has (HB_TAG ('w','g','h','t')) && + !c->plan->pinned_at_default) + { + float weight_class = c->plan->user_axes_location->get (HB_TAG ('w','g','h','t')); + if (!c->serializer->check_assign (os2_prime->usWeightClass, + roundf (hb_clamp (weight_class, 1.0f, 1000.0f)), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + + if (c->plan->user_axes_location->has (HB_TAG ('w','d','t','h')) && + !c->plan->pinned_at_default) + { + float width = c->plan->user_axes_location->get (HB_TAG ('w','d','t','h')); + if (!c->serializer->check_assign (os2_prime->usWidthClass, + roundf (map_wdth_to_widthclass (width)), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + return_trace (true); } diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh index a4c0c4aa17..80d02ffba7 100644 --- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh @@ -102,6 +102,14 @@ struct post if (!serialize (c->serializer, glyph_names)) return_trace (false); + if (c->plan->user_axes_location->has (HB_TAG ('s','l','n','t')) && + !c->plan->pinned_at_default) + { + float italic_angle = c->plan->user_axes_location->get (HB_TAG ('s','l','n','t')); + italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f)); + post_prime->italicAngle.set_float (italic_angle); + } + if (glyph_names && version.major == 2) return_trace (v2X.subset (c)); @@ -133,7 +141,7 @@ struct post } ~accelerator_t () { - hb_free (gids_sorted_by_name.get ()); + hb_free (gids_sorted_by_name.get_acquire ()); table.destroy (); } @@ -160,7 +168,7 @@ struct post if (unlikely (!len)) return false; retry: - uint16_t *gids = gids_sorted_by_name.get (); + uint16_t *gids = gids_sorted_by_name.get_acquire (); if (unlikely (!gids)) { diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh index a5ce3a6c93..c7b57820af 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-14.0.0.txt - * # Date: 2021-05-21, 01:54:00 GMT [KW, RP] - * # Scripts-14.0.0.txt - * # Date: 2021-07-10, 00:35:31 GMT + * # ArabicShaping-15.0.0.txt + * # Date: 2022-02-14, 18:50:00 GMT [KW, RP] + * # Scripts-15.0.0.txt + * # Date: 2022-04-26, 23:15:02 GMT */ #ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh index fd3d8645d1..d7670f2f95 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-14.0.0.txt - * # Date: 2021-05-21, 01:54:00 GMT [KW, RP] - * # Blocks-14.0.0.txt - * # Date: 2021-01-22, 23:29:00 GMT [KW] + * # ArabicShaping-15.0.0.txt + * # Date: 2022-02-14, 18:50:00 GMT [KW, RP] + * # Blocks-15.0.0.txt + * # Date: 2022-01-28, 20:58:00 GMT [KW] * UnicodeData.txt does not have a header. */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh index d3a7cce3de..d52b13f616 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh @@ -53,7 +53,7 @@ enum indic_syllable_type_t { }; -#line 54 "hb-ot-shaper-indic-machine.hh" +#line 57 "hb-ot-shaper-indic-machine.hh" #define indic_syllable_machine_ex_A 9u #define indic_syllable_machine_ex_C 1u #define indic_syllable_machine_ex_CM 16u @@ -75,7 +75,7 @@ enum indic_syllable_type_t { #define indic_syllable_machine_ex_ZWNJ 5u -#line 74 "hb-ot-shaper-indic-machine.hh" +#line 79 "hb-ot-shaper-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 12u, 4u, 12u, 8u, 8u, 5u, 7u, @@ -422,7 +422,7 @@ find_syllables_indic (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 415 "hb-ot-shaper-indic-machine.hh" +#line 426 "hb-ot-shaper-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -438,7 +438,7 @@ find_syllables_indic (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 427 "hb-ot-shaper-indic-machine.hh" +#line 442 "hb-ot-shaper-indic-machine.hh" { int _slen; int _trans; @@ -452,7 +452,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 439 "hb-ot-shaper-indic-machine.hh" +#line 456 "hb-ot-shaper-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -555,7 +555,7 @@ _eof_trans: #line 113 "hb-ot-shaper-indic-machine.rl" {act = 6;} break; -#line 521 "hb-ot-shaper-indic-machine.hh" +#line 559 "hb-ot-shaper-indic-machine.hh" } _again: @@ -564,7 +564,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 528 "hb-ot-shaper-indic-machine.hh" +#line 568 "hb-ot-shaper-indic-machine.hh" } if ( ++p != pe ) diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc index 8994f3ca59..bf6a2757bb 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc @@ -6,12 +6,12 @@ * * on files with these headers: * - * # IndicSyllabicCategory-14.0.0.txt - * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] - * # IndicPositionalCategory-14.0.0.txt - * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] - * # Blocks-14.0.0.txt - * # Date: 2021-01-22, 23:29:00 GMT [KW] + * # IndicSyllabicCategory-15.0.0.txt + * # Date: 2022-05-26, 02:18:00 GMT [KW, RP] + * # IndicPositionalCategory-15.0.0.txt + * # Date: 2022-05-26, 02:18:00 GMT [KW, RP] + * # Blocks-15.0.0.txt + * # Date: 2022-01-28, 20:58:00 GMT [KW] */ #include "hb.hh" @@ -92,7 +92,7 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #define _OT_R OT_Ra /* 14 chars; Ra */ #define _OT_Rf OT_Repha /* 1 chars; Repha */ #define _OT_Rt OT_Robatic /* 3 chars; Robatic */ -#define _OT_SM OT_SM /* 55 chars; SM */ +#define _OT_SM OT_SM /* 56 chars; SM */ #define _OT_S OT_Symbol /* 22 chars; Symbol */ #define _OT_V OT_V /* 172 chars; V */ #define _OT_VA OT_VAbv /* 18 chars; VAbv */ @@ -117,7 +117,7 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #define _POS_R POS_POST_C /* 13 chars; POST_C */ #define _POS_L POS_PRE_C /* 5 chars; PRE_C */ #define _POS_LM POS_PRE_M /* 14 chars; PRE_M */ -#define _POS_SM POS_SMVD /* 129 chars; SMVD */ +#define _POS_SM POS_SMVD /* 130 chars; SMVD */ #pragma GCC diagnostic pop @@ -301,7 +301,7 @@ static const uint16_t indic_table[] = { /* 0CD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), /* 0CE0 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C), /* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0CF0 */ _(X,X), _(CS,C), _(CS,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0CF0 */ _(X,X), _(CS,C), _(CS,C),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X), /* 0CF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), /* Malayalam */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc index 6eb400ab16..55509c1101 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc @@ -276,7 +276,7 @@ struct indic_shape_plan_t { bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const { - hb_codepoint_t glyph = virama_glyph.get_relaxed (); + hb_codepoint_t glyph = virama_glyph; if (unlikely (glyph == (hb_codepoint_t) -1)) { if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph)) @@ -286,7 +286,7 @@ struct indic_shape_plan_t /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph * during shape planning... Instead, overwrite it here. */ - virama_glyph.set_relaxed ((int) glyph); + virama_glyph = (int) glyph; } *pglyph = glyph; @@ -330,7 +330,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan) #ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible; #endif - indic_plan->virama_glyph.set_relaxed (-1); + indic_plan->virama_glyph = -1; /* Use zero-context would_substitute() matching for new-spec of the main * Indic scripts, and scripts with one spec only, but not for old-specs. @@ -992,7 +992,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, * class of I_Cat(H) is desired but has been lost. */ /* We don't call load_virama_glyph(), since we know it's already * loaded. */ - hb_codepoint_t virama_glyph = indic_plan->virama_glyph.get_relaxed (); + hb_codepoint_t virama_glyph = indic_plan->virama_glyph; if (virama_glyph) { for (unsigned int i = start; i < end; i++) diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh index 2c40663bdd..e18bd75ef1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh @@ -48,7 +48,7 @@ enum khmer_syllable_type_t { }; -#line 49 "hb-ot-shaper-khmer-machine.hh" +#line 52 "hb-ot-shaper-khmer-machine.hh" #define khmer_syllable_machine_ex_C 1u #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u #define khmer_syllable_machine_ex_H 4u @@ -66,7 +66,7 @@ enum khmer_syllable_type_t { #define khmer_syllable_machine_ex_ZWNJ 5u -#line 65 "hb-ot-shaper-khmer-machine.hh" +#line 70 "hb-ot-shaper-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, @@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 287 "hb-ot-shaper-khmer-machine.hh" +#line 298 "hb-ot-shaper-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 299 "hb-ot-shaper-khmer-machine.hh" +#line 314 "hb-ot-shaper-khmer-machine.hh" { int _slen; int _trans; @@ -324,7 +324,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 311 "hb-ot-shaper-khmer-machine.hh" +#line 328 "hb-ot-shaper-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -394,7 +394,7 @@ _eof_trans: #line 98 "hb-ot-shaper-khmer-machine.rl" {act = 3;} break; -#line 368 "hb-ot-shaper-khmer-machine.hh" +#line 398 "hb-ot-shaper-khmer-machine.hh" } _again: @@ -403,7 +403,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 375 "hb-ot-shaper-khmer-machine.hh" +#line 407 "hb-ot-shaper-khmer-machine.hh" } if ( ++p != pe ) diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh index 464cf796d4..b109708937 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh @@ -50,7 +50,7 @@ enum myanmar_syllable_type_t { }; -#line 51 "hb-ot-shaper-myanmar-machine.hh" +#line 54 "hb-ot-shaper-myanmar-machine.hh" #define myanmar_syllable_machine_ex_A 9u #define myanmar_syllable_machine_ex_As 32u #define myanmar_syllable_machine_ex_C 1u @@ -77,7 +77,7 @@ enum myanmar_syllable_type_t { #define myanmar_syllable_machine_ex_ZWNJ 5u -#line 76 "hb-ot-shaper-myanmar-machine.hh" +#line 81 "hb-ot-shaper-myanmar-machine.hh" static const unsigned char _myanmar_syllable_machine_trans_keys[] = { 1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u, 5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u, @@ -443,7 +443,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 436 "hb-ot-shaper-myanmar-machine.hh" +#line 447 "hb-ot-shaper-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -459,7 +459,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 448 "hb-ot-shaper-myanmar-machine.hh" +#line 463 "hb-ot-shaper-myanmar-machine.hh" { int _slen; int _trans; @@ -473,7 +473,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 460 "hb-ot-shaper-myanmar-machine.hh" +#line 477 "hb-ot-shaper-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -519,7 +519,7 @@ _eof_trans: #line 113 "hb-ot-shaper-myanmar-machine.rl" {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }} break; -#line 498 "hb-ot-shaper-myanmar-machine.hh" +#line 523 "hb-ot-shaper-myanmar-machine.hh" } _again: @@ -528,7 +528,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 505 "hb-ot-shaper-myanmar-machine.hh" +#line 532 "hb-ot-shaper-myanmar-machine.hh" } if ( ++p != pe ) diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh index 5b3ec05616..41e8a34f3b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh @@ -53,7 +53,7 @@ enum use_syllable_type_t { }; -#line 54 "hb-ot-shaper-use-machine.hh" +#line 57 "hb-ot-shaper-use-machine.hh" #define use_syllable_machine_ex_B 1u #define use_syllable_machine_ex_CGJ 6u #define use_syllable_machine_ex_CMAbv 31u @@ -97,523 +97,669 @@ enum use_syllable_type_t { #define use_syllable_machine_ex_ZWNJ 14u -#line 96 "hb-ot-shaper-use-machine.hh" +#line 101 "hb-ot-shaper-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { - 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, - 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, - 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, - 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 41u, 42u, 42u, 42u, 11u, 53u, 11u, 53u, - 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, - 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, - 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, - 13u, 13u, 4u, 4u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, - 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, - 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, - 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, - 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, - 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, - 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 4u, 4u, 13u, 13u, - 1u, 53u, 11u, 53u, 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, - 0 + 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, + 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, + 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, + 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 11u, 53u, 14u, 42u, 14u, 42u, 11u, 53u, + 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, + 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, + 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, + 1u, 14u, 1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u, + 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, + 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, + 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u, + 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, + 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, + 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, + 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 11u, 53u, + 14u, 42u, 14u, 42u, 1u, 5u, 14u, 52u, 14u, 52u, 14u, 51u, 0 }; static const char _use_syllable_machine_key_spans[] = { - 54, 43, 43, 53, 26, 24, 23, 22, - 2, 1, 25, 25, 25, 1, 25, 32, - 31, 31, 31, 42, 31, 42, 42, 42, - 43, 1, 48, 43, 2, 1, 43, 43, - 53, 26, 24, 23, 22, 2, 1, 25, - 25, 25, 1, 25, 32, 31, 31, 31, - 42, 31, 42, 42, 42, 43, 1, 48, - 1, 1, 43, 43, 53, 26, 24, 23, - 22, 2, 1, 25, 25, 25, 1, 25, - 32, 31, 31, 31, 42, 31, 42, 42, - 42, 43, 1, 48, 43, 43, 53, 26, - 24, 23, 22, 2, 1, 25, 25, 25, - 1, 25, 32, 31, 31, 31, 42, 31, - 42, 42, 42, 43, 1, 48, 1, 1, - 53, 43, 2, 1, 5, 3, 4, 3 + 54, 43, 43, 53, 35, 34, 34, 34, + 33, 33, 1, 35, 35, 35, 14, 35, + 40, 40, 40, 40, 42, 40, 42, 42, + 42, 43, 14, 48, 43, 29, 29, 43, + 43, 53, 35, 34, 34, 34, 33, 33, + 1, 35, 35, 35, 14, 35, 40, 40, + 40, 40, 42, 40, 42, 42, 42, 43, + 14, 14, 48, 2, 11, 43, 43, 53, + 35, 34, 34, 34, 33, 33, 1, 35, + 35, 35, 14, 35, 40, 40, 40, 40, + 42, 40, 42, 42, 42, 43, 14, 14, + 48, 43, 43, 53, 35, 34, 34, 34, + 33, 33, 1, 35, 35, 35, 14, 35, + 40, 40, 40, 40, 42, 40, 42, 42, + 42, 43, 14, 48, 11, 2, 53, 43, + 29, 29, 5, 39, 39, 38 }; static const short _use_syllable_machine_index_offsets[] = { - 0, 55, 99, 143, 197, 224, 249, 273, - 296, 299, 301, 327, 353, 379, 381, 407, - 440, 472, 504, 536, 579, 611, 654, 697, - 740, 784, 786, 835, 879, 882, 884, 928, - 972, 1026, 1053, 1078, 1102, 1125, 1128, 1130, - 1156, 1182, 1208, 1210, 1236, 1269, 1301, 1333, - 1365, 1408, 1440, 1483, 1526, 1569, 1613, 1615, - 1664, 1666, 1668, 1712, 1756, 1810, 1837, 1862, - 1886, 1909, 1912, 1914, 1940, 1966, 1992, 1994, - 2020, 2053, 2085, 2117, 2149, 2192, 2224, 2267, - 2310, 2353, 2397, 2399, 2448, 2492, 2536, 2590, - 2617, 2642, 2666, 2689, 2692, 2694, 2720, 2746, - 2772, 2774, 2800, 2833, 2865, 2897, 2929, 2972, - 3004, 3047, 3090, 3133, 3177, 3179, 3228, 3230, - 3232, 3286, 3330, 3333, 3335, 3341, 3345, 3350 + 0, 55, 99, 143, 197, 233, 268, 303, + 338, 372, 406, 408, 444, 480, 516, 531, + 567, 608, 649, 690, 731, 774, 815, 858, + 901, 944, 988, 1003, 1052, 1096, 1126, 1156, + 1200, 1244, 1298, 1334, 1369, 1404, 1439, 1473, + 1507, 1509, 1545, 1581, 1617, 1632, 1668, 1709, + 1750, 1791, 1832, 1875, 1916, 1959, 2002, 2045, + 2089, 2104, 2119, 2168, 2171, 2183, 2227, 2271, + 2325, 2361, 2396, 2431, 2466, 2500, 2534, 2536, + 2572, 2608, 2644, 2659, 2695, 2736, 2777, 2818, + 2859, 2902, 2943, 2986, 3029, 3072, 3116, 3131, + 3146, 3195, 3239, 3283, 3337, 3373, 3408, 3443, + 3478, 3512, 3546, 3548, 3584, 3620, 3656, 3671, + 3707, 3748, 3789, 3830, 3871, 3914, 3955, 3998, + 4041, 4084, 4128, 4143, 4192, 4204, 4207, 4261, + 4305, 4335, 4365, 4371, 4411, 4451 }; static const unsigned char _use_syllable_machine_indicies[] = { 0, 1, 2, 2, 3, 4, 2, 2, - 2, 2, 2, 5, 6, 7, 2, 2, - 2, 2, 8, 2, 2, 2, 9, 10, + 2, 2, 2, 5, 6, 7, 8, 2, + 2, 2, 9, 2, 2, 2, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 2, 24, 25, 26, + 2, 27, 28, 29, 30, 31, 32, 33, + 30, 34, 2, 35, 2, 36, 2, 38, + 39, 37, 40, 37, 37, 37, 37, 37, + 37, 37, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, + 37, 55, 56, 57, 37, 58, 59, 37, + 60, 61, 62, 63, 60, 37, 37, 37, + 37, 64, 37, 38, 39, 37, 40, 37, + 37, 37, 37, 37, 37, 37, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 51, + 51, 52, 53, 54, 37, 55, 56, 57, + 37, 37, 37, 37, 60, 61, 62, 63, + 60, 37, 37, 37, 37, 64, 37, 38, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 40, 37, 37, 37, + 37, 37, 37, 37, 37, 42, 43, 44, + 45, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 55, 56, 57, 37, 37, + 37, 37, 37, 61, 62, 63, 65, 37, + 37, 37, 37, 42, 37, 40, 37, 37, + 37, 37, 37, 37, 37, 37, 42, 43, + 44, 45, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 55, 56, 57, 37, + 37, 37, 37, 37, 61, 62, 63, 65, + 37, 40, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 43, 44, 45, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 61, 62, 63, 37, 40, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 44, + 45, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 61, 62, 63, 37, 40, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 45, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 61, 62, + 63, 37, 40, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 61, 62, 37, 40, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 62, 37, 40, 37, + 40, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 43, 44, 45, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 55, + 56, 57, 37, 37, 37, 37, 37, 61, + 62, 63, 65, 37, 40, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 43, 44, + 45, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 56, 57, 37, 37, + 37, 37, 37, 61, 62, 63, 65, 37, + 40, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 43, 44, 45, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 57, 37, 37, 37, 37, 37, 61, + 62, 63, 65, 37, 66, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 40, 37, 40, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 43, 44, 45, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 61, 62, 63, 65, 37, 40, + 37, 37, 37, 37, 37, 37, 37, 41, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 52, 53, 54, 37, 55, 56, + 57, 37, 37, 37, 37, 37, 61, 62, + 63, 65, 37, 37, 37, 37, 42, 37, + 40, 37, 37, 37, 37, 37, 37, 37, + 37, 42, 43, 44, 45, 37, 37, 37, + 37, 37, 37, 52, 53, 54, 37, 55, + 56, 57, 37, 37, 37, 37, 37, 61, + 62, 63, 65, 37, 37, 37, 37, 42, + 37, 40, 37, 37, 37, 37, 37, 37, + 37, 37, 42, 43, 44, 45, 37, 37, + 37, 37, 37, 37, 37, 53, 54, 37, + 55, 56, 57, 37, 37, 37, 37, 37, + 61, 62, 63, 65, 37, 37, 37, 37, + 42, 37, 40, 37, 37, 37, 37, 37, + 37, 37, 37, 42, 43, 44, 45, 37, + 37, 37, 37, 37, 37, 37, 37, 54, + 37, 55, 56, 57, 37, 37, 37, 37, + 37, 61, 62, 63, 65, 37, 37, 37, + 37, 42, 37, 67, 37, 40, 37, 37, + 37, 37, 37, 37, 37, 41, 42, 43, + 44, 45, 37, 47, 48, 37, 37, 37, + 52, 53, 54, 37, 55, 56, 57, 37, + 37, 37, 37, 37, 61, 62, 63, 65, + 37, 37, 37, 37, 42, 37, 40, 37, + 37, 37, 37, 37, 37, 37, 37, 42, + 43, 44, 45, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 55, 56, 57, + 37, 37, 37, 37, 37, 61, 62, 63, + 65, 37, 37, 37, 37, 42, 37, 67, + 37, 40, 37, 37, 37, 37, 37, 37, + 37, 41, 42, 43, 44, 45, 37, 37, + 48, 37, 37, 37, 52, 53, 54, 37, + 55, 56, 57, 37, 37, 37, 37, 37, + 61, 62, 63, 65, 37, 37, 37, 37, + 42, 37, 67, 37, 40, 37, 37, 37, + 37, 37, 37, 37, 41, 42, 43, 44, + 45, 37, 37, 37, 37, 37, 37, 52, + 53, 54, 37, 55, 56, 57, 37, 37, + 37, 37, 37, 61, 62, 63, 65, 37, + 37, 37, 37, 42, 37, 67, 37, 40, + 37, 37, 37, 37, 37, 37, 37, 41, + 42, 43, 44, 45, 46, 47, 48, 37, + 37, 37, 52, 53, 54, 37, 55, 56, + 57, 37, 37, 37, 37, 37, 61, 62, + 63, 65, 37, 37, 37, 37, 42, 37, + 38, 39, 37, 40, 37, 37, 37, 37, + 37, 37, 37, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 37, 51, 52, 53, + 54, 37, 55, 56, 57, 37, 37, 37, + 37, 60, 61, 62, 63, 60, 37, 37, + 37, 37, 64, 37, 38, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 40, 37, 38, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 40, 37, 37, 37, 37, 37, 37, 37, + 37, 42, 43, 44, 45, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 55, + 56, 57, 37, 37, 37, 37, 37, 61, + 62, 63, 65, 37, 38, 39, 37, 40, + 37, 37, 37, 37, 37, 37, 37, 41, + 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 37, 55, 56, + 57, 37, 37, 37, 37, 60, 61, 62, + 63, 60, 37, 37, 37, 37, 64, 37, + 40, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 58, 59, 37, 40, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 59, 37, 69, 70, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 1, 81, 82, 83, 84, 68, 85, 86, + 87, 68, 68, 68, 68, 88, 89, 90, + 91, 92, 68, 68, 68, 68, 93, 68, + 69, 70, 68, 71, 68, 68, 68, 68, + 68, 68, 68, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 81, 82, 83, + 84, 68, 85, 86, 87, 68, 68, 68, + 68, 88, 89, 90, 91, 92, 68, 68, + 68, 68, 93, 68, 69, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 68, 73, 74, 75, 76, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 85, 86, 87, 68, 68, 68, 68, 68, + 89, 90, 91, 94, 68, 68, 68, 68, + 73, 68, 71, 68, 68, 68, 68, 68, + 68, 68, 68, 73, 74, 75, 76, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 85, 86, 87, 68, 68, 68, 68, + 68, 89, 90, 91, 94, 68, 71, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 74, 75, 76, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 89, 90, 91, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 75, 76, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 89, 90, 91, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 76, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 89, 90, 91, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 89, 90, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 90, 68, 71, 68, 71, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 74, + 75, 76, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 85, 86, 87, 68, + 68, 68, 68, 68, 89, 90, 91, 94, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 74, 75, 76, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 86, 87, 68, 68, 68, 68, 68, + 89, 90, 91, 94, 68, 71, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 74, + 75, 76, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 87, 68, + 68, 68, 68, 68, 89, 90, 91, 94, + 68, 96, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 97, 95, + 71, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 74, 75, 76, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 89, + 90, 91, 94, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 72, 73, 74, 75, + 76, 68, 68, 68, 68, 68, 68, 82, + 83, 84, 68, 85, 86, 87, 68, 68, + 68, 68, 68, 89, 90, 91, 94, 68, + 68, 68, 68, 73, 68, 71, 68, 68, + 68, 68, 68, 68, 68, 68, 73, 74, + 75, 76, 68, 68, 68, 68, 68, 68, + 82, 83, 84, 68, 85, 86, 87, 68, + 68, 68, 68, 68, 89, 90, 91, 94, + 68, 68, 68, 68, 73, 68, 71, 68, + 68, 68, 68, 68, 68, 68, 68, 73, + 74, 75, 76, 68, 68, 68, 68, 68, + 68, 68, 83, 84, 68, 85, 86, 87, + 68, 68, 68, 68, 68, 89, 90, 91, + 94, 68, 68, 68, 68, 73, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 68, + 73, 74, 75, 76, 68, 68, 68, 68, + 68, 68, 68, 68, 84, 68, 85, 86, + 87, 68, 68, 68, 68, 68, 89, 90, + 91, 94, 68, 68, 68, 68, 73, 68, + 98, 68, 71, 68, 68, 68, 68, 68, + 68, 68, 72, 73, 74, 75, 76, 68, + 78, 79, 68, 68, 68, 82, 83, 84, + 68, 85, 86, 87, 68, 68, 68, 68, + 68, 89, 90, 91, 94, 68, 68, 68, + 68, 73, 68, 71, 68, 68, 68, 68, + 68, 68, 68, 68, 73, 74, 75, 76, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 85, 86, 87, 68, 68, 68, + 68, 68, 89, 90, 91, 94, 68, 68, + 68, 68, 73, 68, 98, 68, 71, 68, + 68, 68, 68, 68, 68, 68, 72, 73, + 74, 75, 76, 68, 68, 79, 68, 68, + 68, 82, 83, 84, 68, 85, 86, 87, + 68, 68, 68, 68, 68, 89, 90, 91, + 94, 68, 68, 68, 68, 73, 68, 98, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 72, 73, 74, 75, 76, 68, 68, + 68, 68, 68, 68, 82, 83, 84, 68, + 85, 86, 87, 68, 68, 68, 68, 68, + 89, 90, 91, 94, 68, 68, 68, 68, + 73, 68, 98, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 72, 73, 74, 75, + 76, 77, 78, 79, 68, 68, 68, 82, + 83, 84, 68, 85, 86, 87, 68, 68, + 68, 68, 68, 89, 90, 91, 94, 68, + 68, 68, 68, 73, 68, 69, 70, 68, + 71, 68, 68, 68, 68, 68, 68, 68, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 68, 81, 82, 83, 84, 68, 85, + 86, 87, 68, 68, 68, 68, 88, 89, + 90, 91, 92, 68, 68, 68, 68, 93, + 68, 69, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 100, 99, + 69, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 97, 95, 69, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 68, 73, 74, 75, + 76, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 85, 86, 87, 68, 68, + 68, 68, 68, 89, 90, 91, 94, 68, + 102, 103, 101, 3, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 105, 104, 106, + 107, 68, 71, 68, 68, 68, 68, 68, + 68, 68, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, + 68, 122, 123, 124, 68, 58, 59, 68, + 125, 126, 127, 128, 129, 68, 68, 68, + 68, 130, 68, 106, 107, 68, 71, 68, + 68, 68, 68, 68, 68, 68, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 118, + 118, 119, 120, 121, 68, 122, 123, 124, + 68, 68, 68, 68, 125, 126, 127, 128, + 129, 68, 68, 68, 68, 130, 68, 106, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 68, 109, 110, 111, + 112, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 122, 123, 124, 68, 68, + 68, 68, 68, 126, 127, 128, 131, 68, + 68, 68, 68, 109, 68, 71, 68, 68, + 68, 68, 68, 68, 68, 68, 109, 110, + 111, 112, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 122, 123, 124, 68, + 68, 68, 68, 68, 126, 127, 128, 131, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 110, 111, 112, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 126, 127, 128, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 111, + 112, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 126, 127, 128, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 112, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 126, 127, + 128, 68, 71, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 126, 127, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 127, 68, 71, 68, + 71, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 110, 111, 112, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 122, + 123, 124, 68, 68, 68, 68, 68, 126, + 127, 128, 131, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 110, 111, + 112, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 123, 124, 68, 68, + 68, 68, 68, 126, 127, 128, 131, 68, + 71, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 110, 111, 112, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 124, 68, 68, 68, 68, 68, 126, + 127, 128, 131, 68, 132, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, + 95, 97, 95, 71, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 110, 111, 112, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 126, 127, 128, 131, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 108, + 109, 110, 111, 112, 68, 68, 68, 68, + 68, 68, 119, 120, 121, 68, 122, 123, + 124, 68, 68, 68, 68, 68, 126, 127, + 128, 131, 68, 68, 68, 68, 109, 68, + 71, 68, 68, 68, 68, 68, 68, 68, + 68, 109, 110, 111, 112, 68, 68, 68, + 68, 68, 68, 119, 120, 121, 68, 122, + 123, 124, 68, 68, 68, 68, 68, 126, + 127, 128, 131, 68, 68, 68, 68, 109, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 68, 109, 110, 111, 112, 68, 68, + 68, 68, 68, 68, 68, 120, 121, 68, + 122, 123, 124, 68, 68, 68, 68, 68, + 126, 127, 128, 131, 68, 68, 68, 68, + 109, 68, 71, 68, 68, 68, 68, 68, + 68, 68, 68, 109, 110, 111, 112, 68, + 68, 68, 68, 68, 68, 68, 68, 121, + 68, 122, 123, 124, 68, 68, 68, 68, + 68, 126, 127, 128, 131, 68, 68, 68, + 68, 109, 68, 133, 68, 71, 68, 68, + 68, 68, 68, 68, 68, 108, 109, 110, + 111, 112, 68, 114, 115, 68, 68, 68, + 119, 120, 121, 68, 122, 123, 124, 68, + 68, 68, 68, 68, 126, 127, 128, 131, + 68, 68, 68, 68, 109, 68, 71, 68, + 68, 68, 68, 68, 68, 68, 68, 109, + 110, 111, 112, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 122, 123, 124, + 68, 68, 68, 68, 68, 126, 127, 128, + 131, 68, 68, 68, 68, 109, 68, 133, + 68, 71, 68, 68, 68, 68, 68, 68, + 68, 108, 109, 110, 111, 112, 68, 68, + 115, 68, 68, 68, 119, 120, 121, 68, + 122, 123, 124, 68, 68, 68, 68, 68, + 126, 127, 128, 131, 68, 68, 68, 68, + 109, 68, 133, 68, 71, 68, 68, 68, + 68, 68, 68, 68, 108, 109, 110, 111, + 112, 68, 68, 68, 68, 68, 68, 119, + 120, 121, 68, 122, 123, 124, 68, 68, + 68, 68, 68, 126, 127, 128, 131, 68, + 68, 68, 68, 109, 68, 133, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 108, + 109, 110, 111, 112, 113, 114, 115, 68, + 68, 68, 119, 120, 121, 68, 122, 123, + 124, 68, 68, 68, 68, 68, 126, 127, + 128, 131, 68, 68, 68, 68, 109, 68, + 106, 107, 68, 71, 68, 68, 68, 68, + 68, 68, 68, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 68, 118, 119, 120, + 121, 68, 122, 123, 124, 68, 68, 68, + 68, 125, 126, 127, 128, 129, 68, 68, + 68, 68, 130, 68, 106, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 100, 99, 106, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, + 97, 95, 106, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 71, + 68, 68, 68, 68, 68, 68, 68, 68, + 109, 110, 111, 112, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 122, 123, + 124, 68, 68, 68, 68, 68, 126, 127, + 128, 131, 68, 106, 107, 68, 71, 68, + 68, 68, 68, 68, 68, 68, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 68, 122, 123, 124, + 68, 68, 68, 68, 125, 126, 127, 128, + 129, 68, 68, 68, 68, 130, 68, 5, + 6, 134, 8, 134, 134, 134, 134, 134, + 134, 134, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 20, 20, 21, 22, 23, + 134, 24, 25, 26, 134, 134, 134, 134, + 30, 31, 32, 33, 30, 134, 134, 134, + 134, 36, 134, 5, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 8, 134, 134, 134, 134, 134, 134, 134, + 134, 11, 12, 13, 14, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 24, + 25, 26, 134, 134, 134, 134, 134, 31, + 32, 33, 135, 134, 134, 134, 134, 11, + 134, 8, 134, 134, 134, 134, 134, 134, + 134, 134, 11, 12, 13, 14, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 24, 25, 26, 134, 134, 134, 134, 134, + 31, 32, 33, 135, 134, 8, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 12, + 13, 14, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 31, 32, 33, 134, + 8, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 13, 14, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 31, + 32, 33, 134, 8, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 14, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 31, 32, 33, 134, 8, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 31, 32, 134, + 8, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 32, 134, 8, 134, 8, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 12, 13, + 14, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 24, 25, 26, 134, 134, + 134, 134, 134, 31, 32, 33, 135, 134, + 8, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 12, 13, 14, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 25, 26, 134, 134, 134, 134, 134, 31, + 32, 33, 135, 134, 8, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 12, 13, + 14, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 26, 134, 134, + 134, 134, 134, 31, 32, 33, 135, 134, + 136, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 8, 134, 8, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 12, 13, 14, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 31, 32, + 33, 135, 134, 8, 134, 134, 134, 134, + 134, 134, 134, 10, 11, 12, 13, 14, + 134, 134, 134, 134, 134, 134, 21, 22, + 23, 134, 24, 25, 26, 134, 134, 134, + 134, 134, 31, 32, 33, 135, 134, 134, + 134, 134, 11, 134, 8, 134, 134, 134, + 134, 134, 134, 134, 134, 11, 12, 13, + 14, 134, 134, 134, 134, 134, 134, 21, + 22, 23, 134, 24, 25, 26, 134, 134, + 134, 134, 134, 31, 32, 33, 135, 134, + 134, 134, 134, 11, 134, 8, 134, 134, + 134, 134, 134, 134, 134, 134, 11, 12, + 13, 14, 134, 134, 134, 134, 134, 134, + 134, 22, 23, 134, 24, 25, 26, 134, + 134, 134, 134, 134, 31, 32, 33, 135, + 134, 134, 134, 134, 11, 134, 8, 134, + 134, 134, 134, 134, 134, 134, 134, 11, + 12, 13, 14, 134, 134, 134, 134, 134, + 134, 134, 134, 23, 134, 24, 25, 26, + 134, 134, 134, 134, 134, 31, 32, 33, + 135, 134, 134, 134, 134, 11, 134, 137, + 134, 8, 134, 134, 134, 134, 134, 134, + 134, 10, 11, 12, 13, 14, 134, 16, + 17, 134, 134, 134, 21, 22, 23, 134, + 24, 25, 26, 134, 134, 134, 134, 134, + 31, 32, 33, 135, 134, 134, 134, 134, + 11, 134, 8, 134, 134, 134, 134, 134, + 134, 134, 134, 11, 12, 13, 14, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 24, 25, 26, 134, 134, 134, 134, + 134, 31, 32, 33, 135, 134, 134, 134, + 134, 11, 134, 137, 134, 8, 134, 134, + 134, 134, 134, 134, 134, 10, 11, 12, + 13, 14, 134, 134, 17, 134, 134, 134, + 21, 22, 23, 134, 24, 25, 26, 134, + 134, 134, 134, 134, 31, 32, 33, 135, + 134, 134, 134, 134, 11, 134, 137, 134, + 8, 134, 134, 134, 134, 134, 134, 134, + 10, 11, 12, 13, 14, 134, 134, 134, + 134, 134, 134, 21, 22, 23, 134, 24, + 25, 26, 134, 134, 134, 134, 134, 31, + 32, 33, 135, 134, 134, 134, 134, 11, + 134, 137, 134, 8, 134, 134, 134, 134, + 134, 134, 134, 10, 11, 12, 13, 14, + 15, 16, 17, 134, 134, 134, 21, 22, + 23, 134, 24, 25, 26, 134, 134, 134, + 134, 134, 31, 32, 33, 135, 134, 134, + 134, 134, 11, 134, 5, 6, 134, 8, + 134, 134, 134, 134, 134, 134, 134, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 2, 23, 24, 25, - 2, 26, 27, 28, 29, 30, 31, 32, - 29, 33, 2, 34, 2, 35, 2, 37, - 38, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, - 36, 53, 54, 55, 36, 56, 57, 36, - 58, 59, 60, 61, 58, 36, 36, 36, - 36, 62, 36, 37, 38, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 49, - 49, 50, 51, 52, 36, 53, 54, 55, - 36, 36, 36, 36, 58, 59, 60, 61, - 58, 36, 36, 36, 36, 62, 36, 37, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 40, 41, 42, - 43, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 53, 54, 55, 36, 36, - 36, 36, 36, 59, 60, 61, 63, 36, - 36, 36, 36, 40, 36, 40, 41, 42, - 43, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 53, 54, 55, 36, 36, - 36, 36, 36, 59, 60, 61, 63, 36, - 41, 42, 43, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 59, 60, 61, - 36, 42, 43, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 59, 60, 61, - 36, 43, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 59, 60, 61, 36, - 59, 60, 36, 60, 36, 41, 42, 43, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 53, 54, 55, 36, 36, 36, - 36, 36, 59, 60, 61, 63, 36, 41, - 42, 43, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 54, 55, 36, - 36, 36, 36, 36, 59, 60, 61, 63, - 36, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 55, 36, 36, 36, 36, 36, 59, 60, - 61, 63, 36, 64, 36, 41, 42, 43, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 59, 60, 61, 63, 36, 39, - 40, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 50, 51, 52, 36, 53, 54, - 55, 36, 36, 36, 36, 36, 59, 60, - 61, 63, 36, 36, 36, 36, 40, 36, - 40, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 50, 51, 52, 36, 53, 54, - 55, 36, 36, 36, 36, 36, 59, 60, - 61, 63, 36, 36, 36, 36, 40, 36, - 40, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 36, 51, 52, 36, 53, 54, - 55, 36, 36, 36, 36, 36, 59, 60, - 61, 63, 36, 36, 36, 36, 40, 36, - 40, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 36, 36, 52, 36, 53, 54, - 55, 36, 36, 36, 36, 36, 59, 60, - 61, 63, 36, 36, 36, 36, 40, 36, - 65, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 39, 40, 41, 42, 43, 36, - 45, 46, 36, 36, 36, 50, 51, 52, - 36, 53, 54, 55, 36, 36, 36, 36, - 36, 59, 60, 61, 63, 36, 36, 36, - 36, 40, 36, 40, 41, 42, 43, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 53, 54, 55, 36, 36, 36, 36, - 36, 59, 60, 61, 63, 36, 36, 36, - 36, 40, 36, 65, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 39, 40, 41, - 42, 43, 36, 36, 46, 36, 36, 36, - 50, 51, 52, 36, 53, 54, 55, 36, - 36, 36, 36, 36, 59, 60, 61, 63, - 36, 36, 36, 36, 40, 36, 65, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 39, 40, 41, 42, 43, 36, 36, 36, - 36, 36, 36, 50, 51, 52, 36, 53, - 54, 55, 36, 36, 36, 36, 36, 59, - 60, 61, 63, 36, 36, 36, 36, 40, - 36, 65, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 39, 40, 41, 42, 43, - 44, 45, 46, 36, 36, 36, 50, 51, - 52, 36, 53, 54, 55, 36, 36, 36, - 36, 36, 59, 60, 61, 63, 36, 36, - 36, 36, 40, 36, 37, 38, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 36, 49, 50, 51, 52, 36, 53, 54, - 55, 36, 36, 36, 36, 58, 59, 60, - 61, 58, 36, 36, 36, 36, 62, 36, - 37, 36, 37, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 40, 41, 42, 43, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 53, 54, - 55, 36, 36, 36, 36, 36, 59, 60, - 61, 63, 36, 37, 38, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 36, 53, 54, 55, - 36, 36, 36, 36, 58, 59, 60, 61, - 58, 36, 36, 36, 36, 62, 36, 56, - 57, 36, 57, 36, 67, 68, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 69, - 70, 71, 72, 73, 74, 75, 76, 77, - 1, 78, 79, 80, 81, 66, 82, 83, - 84, 66, 66, 66, 66, 85, 86, 87, - 88, 89, 66, 66, 66, 66, 90, 66, - 67, 68, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 78, 79, 80, - 81, 66, 82, 83, 84, 66, 66, 66, - 66, 85, 86, 87, 88, 89, 66, 66, - 66, 66, 90, 66, 67, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 70, 71, 72, 73, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 82, 83, 84, 66, 66, 66, 66, 66, - 86, 87, 88, 91, 66, 66, 66, 66, - 70, 66, 70, 71, 72, 73, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 82, 83, 84, 66, 66, 66, 66, 66, - 86, 87, 88, 91, 66, 71, 72, 73, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 86, 87, 88, 66, 72, 73, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 86, 87, 88, 66, 73, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 86, 87, 88, 66, 86, 87, 66, - 87, 66, 71, 72, 73, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 82, - 83, 84, 66, 66, 66, 66, 66, 86, - 87, 88, 91, 66, 71, 72, 73, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 83, 84, 66, 66, 66, 66, - 66, 86, 87, 88, 91, 66, 71, 72, - 73, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 84, 66, 66, - 66, 66, 66, 86, 87, 88, 91, 66, - 93, 92, 71, 72, 73, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 86, - 87, 88, 91, 66, 69, 70, 71, 72, - 73, 66, 66, 66, 66, 66, 66, 79, - 80, 81, 66, 82, 83, 84, 66, 66, - 66, 66, 66, 86, 87, 88, 91, 66, - 66, 66, 66, 70, 66, 70, 71, 72, - 73, 66, 66, 66, 66, 66, 66, 79, - 80, 81, 66, 82, 83, 84, 66, 66, - 66, 66, 66, 86, 87, 88, 91, 66, - 66, 66, 66, 70, 66, 70, 71, 72, - 73, 66, 66, 66, 66, 66, 66, 66, - 80, 81, 66, 82, 83, 84, 66, 66, - 66, 66, 66, 86, 87, 88, 91, 66, - 66, 66, 66, 70, 66, 70, 71, 72, - 73, 66, 66, 66, 66, 66, 66, 66, - 66, 81, 66, 82, 83, 84, 66, 66, - 66, 66, 66, 86, 87, 88, 91, 66, - 66, 66, 66, 70, 66, 94, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 69, - 70, 71, 72, 73, 66, 75, 76, 66, - 66, 66, 79, 80, 81, 66, 82, 83, - 84, 66, 66, 66, 66, 66, 86, 87, - 88, 91, 66, 66, 66, 66, 70, 66, - 70, 71, 72, 73, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 82, 83, - 84, 66, 66, 66, 66, 66, 86, 87, - 88, 91, 66, 66, 66, 66, 70, 66, - 94, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 69, 70, 71, 72, 73, 66, - 66, 76, 66, 66, 66, 79, 80, 81, - 66, 82, 83, 84, 66, 66, 66, 66, - 66, 86, 87, 88, 91, 66, 66, 66, - 66, 70, 66, 94, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 69, 70, 71, - 72, 73, 66, 66, 66, 66, 66, 66, - 79, 80, 81, 66, 82, 83, 84, 66, - 66, 66, 66, 66, 86, 87, 88, 91, - 66, 66, 66, 66, 70, 66, 94, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 69, 70, 71, 72, 73, 74, 75, 76, - 66, 66, 66, 79, 80, 81, 66, 82, - 83, 84, 66, 66, 66, 66, 66, 86, - 87, 88, 91, 66, 66, 66, 66, 70, - 66, 67, 68, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 66, 78, 79, - 80, 81, 66, 82, 83, 84, 66, 66, - 66, 66, 85, 86, 87, 88, 89, 66, - 66, 66, 66, 90, 66, 67, 95, 67, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 70, 71, 72, - 73, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 82, 83, 84, 66, 66, - 66, 66, 66, 86, 87, 88, 91, 66, - 97, 96, 3, 98, 99, 100, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 101, - 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 66, 115, 116, - 117, 66, 56, 57, 66, 118, 119, 120, - 88, 121, 66, 66, 66, 66, 122, 66, - 99, 100, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 111, 111, 112, 113, - 114, 66, 115, 116, 117, 66, 66, 66, - 66, 118, 119, 120, 88, 121, 66, 66, - 66, 66, 122, 66, 99, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 102, 103, 104, 105, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 115, 116, 117, 66, 66, 66, 66, 66, - 119, 120, 88, 123, 66, 66, 66, 66, - 102, 66, 102, 103, 104, 105, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 115, 116, 117, 66, 66, 66, 66, 66, - 119, 120, 88, 123, 66, 103, 104, 105, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 119, 120, 88, 66, 104, 105, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 119, 120, 88, 66, 105, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 119, 120, 88, 66, 119, 120, 66, - 120, 66, 103, 104, 105, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 115, - 116, 117, 66, 66, 66, 66, 66, 119, - 120, 88, 123, 66, 103, 104, 105, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 116, 117, 66, 66, 66, 66, - 66, 119, 120, 88, 123, 66, 103, 104, - 105, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 117, 66, 66, - 66, 66, 66, 119, 120, 88, 123, 66, - 124, 92, 103, 104, 105, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 119, - 120, 88, 123, 66, 101, 102, 103, 104, - 105, 66, 66, 66, 66, 66, 66, 112, - 113, 114, 66, 115, 116, 117, 66, 66, - 66, 66, 66, 119, 120, 88, 123, 66, - 66, 66, 66, 102, 66, 102, 103, 104, - 105, 66, 66, 66, 66, 66, 66, 112, - 113, 114, 66, 115, 116, 117, 66, 66, - 66, 66, 66, 119, 120, 88, 123, 66, - 66, 66, 66, 102, 66, 102, 103, 104, - 105, 66, 66, 66, 66, 66, 66, 66, - 113, 114, 66, 115, 116, 117, 66, 66, - 66, 66, 66, 119, 120, 88, 123, 66, - 66, 66, 66, 102, 66, 102, 103, 104, - 105, 66, 66, 66, 66, 66, 66, 66, - 66, 114, 66, 115, 116, 117, 66, 66, - 66, 66, 66, 119, 120, 88, 123, 66, - 66, 66, 66, 102, 66, 125, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 101, - 102, 103, 104, 105, 66, 107, 108, 66, - 66, 66, 112, 113, 114, 66, 115, 116, - 117, 66, 66, 66, 66, 66, 119, 120, - 88, 123, 66, 66, 66, 66, 102, 66, - 102, 103, 104, 105, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 115, 116, - 117, 66, 66, 66, 66, 66, 119, 120, - 88, 123, 66, 66, 66, 66, 102, 66, - 125, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 101, 102, 103, 104, 105, 66, - 66, 108, 66, 66, 66, 112, 113, 114, - 66, 115, 116, 117, 66, 66, 66, 66, - 66, 119, 120, 88, 123, 66, 66, 66, - 66, 102, 66, 125, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 101, 102, 103, - 104, 105, 66, 66, 66, 66, 66, 66, - 112, 113, 114, 66, 115, 116, 117, 66, - 66, 66, 66, 66, 119, 120, 88, 123, - 66, 66, 66, 66, 102, 66, 125, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 101, 102, 103, 104, 105, 106, 107, 108, - 66, 66, 66, 112, 113, 114, 66, 115, - 116, 117, 66, 66, 66, 66, 66, 119, - 120, 88, 123, 66, 66, 66, 66, 102, - 66, 99, 100, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 66, 111, 112, - 113, 114, 66, 115, 116, 117, 66, 66, - 66, 66, 118, 119, 120, 88, 121, 66, - 66, 66, 66, 122, 66, 99, 95, 99, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 102, 103, 104, - 105, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 115, 116, 117, 66, 66, - 66, 66, 66, 119, 120, 88, 123, 66, - 99, 100, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, - 114, 66, 115, 116, 117, 66, 66, 66, - 66, 118, 119, 120, 88, 121, 66, 66, - 66, 66, 122, 66, 5, 6, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 9, + 134, 20, 21, 22, 23, 134, 24, 25, + 26, 134, 134, 134, 134, 30, 31, 32, + 33, 30, 134, 134, 134, 134, 36, 134, + 5, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 8, 134, 5, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 8, 134, 134, 134, + 134, 134, 134, 134, 134, 11, 12, 13, + 14, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 24, 25, 26, 134, 134, + 134, 134, 134, 31, 32, 33, 135, 134, + 138, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 8, 134, 7, 8, 134, 1, + 134, 134, 134, 1, 134, 134, 134, 134, + 134, 5, 6, 7, 8, 134, 134, 134, + 134, 134, 134, 134, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 134, 24, 25, 26, 134, 27, + 28, 134, 30, 31, 32, 33, 30, 134, + 134, 134, 134, 36, 134, 5, 6, 134, + 8, 134, 134, 134, 134, 134, 134, 134, 10, 11, 12, 13, 14, 15, 16, 17, - 19, 19, 20, 21, 22, 126, 23, 24, - 25, 126, 126, 126, 126, 29, 30, 31, - 32, 29, 126, 126, 126, 126, 35, 126, - 5, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 10, 11, - 12, 13, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 23, 24, 25, 126, - 126, 126, 126, 126, 30, 31, 32, 127, - 126, 126, 126, 126, 10, 126, 10, 11, - 12, 13, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 23, 24, 25, 126, - 126, 126, 126, 126, 30, 31, 32, 127, - 126, 11, 12, 13, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 30, 31, - 32, 126, 12, 13, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 30, 31, - 32, 126, 13, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 30, 31, 32, - 126, 30, 31, 126, 31, 126, 11, 12, - 13, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 23, 24, 25, 126, 126, - 126, 126, 126, 30, 31, 32, 127, 126, - 11, 12, 13, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 24, 25, - 126, 126, 126, 126, 126, 30, 31, 32, - 127, 126, 11, 12, 13, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 25, 126, 126, 126, 126, 126, 30, - 31, 32, 127, 126, 128, 126, 11, 12, - 13, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 30, 31, 32, 127, 126, - 9, 10, 11, 12, 13, 126, 126, 126, - 126, 126, 126, 20, 21, 22, 126, 23, - 24, 25, 126, 126, 126, 126, 126, 30, - 31, 32, 127, 126, 126, 126, 126, 10, - 126, 10, 11, 12, 13, 126, 126, 126, - 126, 126, 126, 20, 21, 22, 126, 23, - 24, 25, 126, 126, 126, 126, 126, 30, - 31, 32, 127, 126, 126, 126, 126, 10, - 126, 10, 11, 12, 13, 126, 126, 126, - 126, 126, 126, 126, 21, 22, 126, 23, - 24, 25, 126, 126, 126, 126, 126, 30, - 31, 32, 127, 126, 126, 126, 126, 10, - 126, 10, 11, 12, 13, 126, 126, 126, - 126, 126, 126, 126, 126, 22, 126, 23, - 24, 25, 126, 126, 126, 126, 126, 30, - 31, 32, 127, 126, 126, 126, 126, 10, - 126, 129, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 9, 10, 11, 12, 13, - 126, 15, 16, 126, 126, 126, 20, 21, - 22, 126, 23, 24, 25, 126, 126, 126, - 126, 126, 30, 31, 32, 127, 126, 126, - 126, 126, 10, 126, 10, 11, 12, 13, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 23, 24, 25, 126, 126, 126, - 126, 126, 30, 31, 32, 127, 126, 126, - 126, 126, 10, 126, 129, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 9, 10, - 11, 12, 13, 126, 126, 16, 126, 126, - 126, 20, 21, 22, 126, 23, 24, 25, - 126, 126, 126, 126, 126, 30, 31, 32, - 127, 126, 126, 126, 126, 10, 126, 129, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 9, 10, 11, 12, 13, 126, 126, - 126, 126, 126, 126, 20, 21, 22, 126, - 23, 24, 25, 126, 126, 126, 126, 126, - 30, 31, 32, 127, 126, 126, 126, 126, - 10, 126, 129, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 9, 10, 11, 12, - 13, 14, 15, 16, 126, 126, 126, 20, - 21, 22, 126, 23, 24, 25, 126, 126, - 126, 126, 126, 30, 31, 32, 127, 126, - 126, 126, 126, 10, 126, 5, 6, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 126, 19, 20, 21, 22, 126, 23, - 24, 25, 126, 126, 126, 126, 29, 30, - 31, 32, 29, 126, 126, 126, 126, 35, - 126, 5, 126, 5, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 10, 11, 12, 13, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 23, - 24, 25, 126, 126, 126, 126, 126, 30, - 31, 32, 127, 126, 130, 126, 7, 126, - 1, 126, 126, 126, 1, 126, 126, 126, - 126, 126, 5, 6, 7, 126, 126, 126, - 126, 126, 126, 126, 126, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 126, 23, 24, 25, 126, - 26, 27, 126, 29, 30, 31, 32, 29, - 126, 126, 126, 126, 35, 126, 5, 6, - 126, 126, 126, 126, 126, 126, 126, 126, - 126, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 126, - 23, 24, 25, 126, 126, 126, 126, 29, - 30, 31, 32, 29, 126, 126, 126, 126, - 35, 126, 26, 27, 126, 27, 126, 1, - 131, 131, 131, 1, 131, 133, 132, 33, - 132, 33, 133, 132, 133, 132, 33, 132, - 34, 132, 0 + 18, 19, 20, 21, 22, 23, 134, 24, + 25, 26, 134, 134, 134, 134, 30, 31, + 32, 33, 30, 134, 134, 134, 134, 36, + 134, 8, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 27, 28, 134, 8, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 28, 134, 1, 139, 139, + 139, 1, 139, 141, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 142, + 140, 34, 140, 141, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 34, 142, + 140, 142, 140, 141, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 34, 140, + 35, 140, 0 }; static const char _use_syllable_machine_trans_targs[] = { - 1, 30, 0, 56, 58, 85, 86, 110, - 112, 98, 87, 88, 89, 90, 102, 104, - 105, 106, 113, 107, 99, 100, 101, 93, - 94, 95, 114, 115, 116, 108, 91, 92, - 0, 117, 119, 109, 0, 2, 3, 15, - 4, 5, 6, 7, 19, 21, 22, 23, - 27, 24, 16, 17, 18, 10, 11, 12, - 28, 29, 25, 8, 9, 0, 26, 13, - 14, 20, 0, 31, 32, 44, 33, 34, - 35, 36, 48, 50, 51, 52, 53, 45, - 46, 47, 39, 40, 41, 54, 37, 38, - 0, 54, 55, 42, 0, 43, 49, 0, - 0, 57, 0, 59, 60, 72, 61, 62, - 63, 64, 76, 78, 79, 80, 84, 81, - 73, 74, 75, 67, 68, 69, 82, 65, - 66, 82, 83, 70, 71, 77, 0, 96, - 97, 103, 111, 0, 0, 118 + 1, 31, 0, 59, 61, 90, 91, 116, + 0, 118, 104, 92, 93, 94, 95, 108, + 110, 111, 112, 119, 113, 105, 106, 107, + 99, 100, 101, 120, 121, 122, 114, 96, + 97, 98, 123, 125, 115, 0, 2, 3, + 0, 16, 4, 5, 6, 7, 20, 22, + 23, 24, 28, 25, 17, 18, 19, 11, + 12, 13, 29, 30, 26, 8, 9, 10, + 27, 14, 15, 21, 0, 32, 33, 0, + 46, 34, 35, 36, 37, 50, 52, 53, + 54, 55, 47, 48, 49, 41, 42, 43, + 56, 38, 39, 40, 57, 58, 44, 0, + 45, 0, 51, 0, 0, 0, 60, 0, + 0, 0, 62, 63, 76, 64, 65, 66, + 67, 80, 82, 83, 84, 89, 85, 77, + 78, 79, 71, 72, 73, 86, 68, 69, + 70, 87, 88, 74, 75, 81, 0, 102, + 103, 109, 117, 0, 0, 0, 124 }; static const char _use_syllable_machine_trans_actions[] = { 0, 0, 3, 0, 0, 0, 0, 0, + 4, 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, 5, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 0, 0, - 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 8, 0, 0, - 9, 10, 0, 0, 11, 0, 0, 12, - 13, 0, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, + 0, 10, 0, 11, 12, 13, 0, 14, + 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 8, 0, - 0, 10, 0, 0, 0, 0, 15, 0, - 0, 0, 0, 16, 17, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 18, 19, 20, 0 }; static const char _use_syllable_machine_to_state_actions[] = { @@ -631,7 +777,8 @@ static const char _use_syllable_machine_to_state_actions[] = { 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 }; static const char _use_syllable_machine_from_state_actions[] = { @@ -649,25 +796,27 @@ static const char _use_syllable_machine_from_state_actions[] = { 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 }; static const short _use_syllable_machine_eof_trans[] = { - 0, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 93, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 96, 67, - 97, 99, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 93, 67, - 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 96, 67, 67, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 132, 133, 133, 133 + 0, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 96, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 100, 96, 69, 102, 105, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 96, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 100, 96, + 69, 69, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 140, 141, 141, 141 }; static const int use_syllable_machine_start = 0; @@ -780,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int act HB_UNUSED; int cs; -#line 773 "hb-ot-shaper-use-machine.hh" +#line 933 "hb-ot-shaper-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -793,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 782 "hb-ot-shaper-use-machine.hh" +#line 946 "hb-ot-shaper-use-machine.hh" { int _slen; int _trans; @@ -807,7 +956,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 794 "hb-ot-shaper-use-machine.hh" +#line 960 "hb-ot-shaper-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -825,14 +974,34 @@ _eof_trans: goto _again; switch ( _use_syllable_machine_trans_actions[_trans] ) { - case 9: + case 12: +#line 170 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_virama_terminated_cluster); }} + break; + case 10: +#line 171 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_sakot_terminated_cluster); }} + break; + case 8: #line 172 "hb-ot-shaper-use-machine.rl" {te = p+1;{ found_syllable (use_standard_cluster); }} break; + case 16: +#line 173 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_number_joiner_terminated_cluster); }} + break; + case 14: +#line 174 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_numeral_cluster); }} + break; case 6: #line 175 "hb-ot-shaper-use-machine.rl" {te = p+1;{ found_syllable (use_symbol_cluster); }} break; + case 20: +#line 176 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_hieroglyph_cluster); }} + break; case 4: #line 177 "hb-ot-shaper-use-machine.rl" {te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} @@ -842,6 +1011,10 @@ _eof_trans: {te = p+1;{ found_syllable (use_non_cluster); }} break; case 11: +#line 170 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }} + break; + case 9: #line 171 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }} break; @@ -849,7 +1022,7 @@ _eof_trans: #line 172 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_standard_cluster); }} break; - case 14: + case 15: #line 173 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }} break; @@ -861,43 +1034,19 @@ _eof_trans: #line 175 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_symbol_cluster); }} break; - case 17: + case 19: #line 176 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }} break; - case 15: + case 17: #line 177 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} break; - case 16: + case 18: #line 178 "hb-ot-shaper-use-machine.rl" {te = p;p--;{ found_syllable (use_non_cluster); }} break; - case 12: -#line 1 "NONE" - { switch( act ) { - case 1: - {{p = ((te))-1;} found_syllable (use_virama_terminated_cluster); } - break; - case 2: - {{p = ((te))-1;} found_syllable (use_sakot_terminated_cluster); } - break; - } - } - break; - case 8: -#line 1 "NONE" - {te = p+1;} -#line 170 "hb-ot-shaper-use-machine.rl" - {act = 1;} - break; - case 10: -#line 1 "NONE" - {te = p+1;} -#line 171 "hb-ot-shaper-use-machine.rl" - {act = 2;} - break; -#line 866 "hb-ot-shaper-use-machine.hh" +#line 1050 "hb-ot-shaper-use-machine.hh" } _again: @@ -906,7 +1055,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 873 "hb-ot-shaper-use-machine.hh" +#line 1059 "hb-ot-shaper-use-machine.hh" } if ( ++p != pe ) diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh index e45ea30e60..6395d689ae 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh @@ -6,18 +6,18 @@ * * on files with these headers: * - * # IndicSyllabicCategory-14.0.0.txt - * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] - * # IndicPositionalCategory-14.0.0.txt - * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] - * # ArabicShaping-14.0.0.txt - * # Date: 2021-05-21, 01:54:00 GMT [KW, RP] - * # DerivedCoreProperties-14.0.0.txt - * # Date: 2021-08-12, 23:12:53 GMT - * # Blocks-14.0.0.txt - * # Date: 2021-01-22, 23:29:00 GMT [KW] - * # Scripts-14.0.0.txt - * # Date: 2021-07-10, 00:35:31 GMT + * # IndicSyllabicCategory-15.0.0.txt + * # Date: 2022-05-26, 02:18:00 GMT [KW, RP] + * # IndicPositionalCategory-15.0.0.txt + * # Date: 2022-05-26, 02:18:00 GMT [KW, RP] + * # ArabicShaping-15.0.0.txt + * # Date: 2022-02-14, 18:50:00 GMT [KW, RP] + * # DerivedCoreProperties-15.0.0.txt + * # Date: 2022-08-05, 22:17:05 GMT + * # Blocks-15.0.0.txt + * # Date: 2022-01-28, 20:58:00 GMT [KW] + * # Scripts-15.0.0.txt + * # Date: 2022-04-26, 23:15:02 GMT * # Override values For Indic_Syllabic_Category * # Not derivable * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 @@ -90,7 +90,7 @@ #pragma GCC diagnostic pop static const uint8_t -hb_use_u8[3083] = +hb_use_u8[3115] = { 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, @@ -114,22 +114,22 @@ hb_use_u8[3083] = 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, 2, 2, 2, 2, 2, 2, 2, 2, 50, 51, 2, 52, 2, 2, 53, 2, 2, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 2, 64, 65, 2, 66, 67, 68, 69, - 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 2, - 2, 80, 80, 80, 80, 80, 80, 80, 80, 81, 2, 2, 2, 2, 2, 2, + 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 80, + 2, 81, 81, 81, 81, 81, 81, 81, 81, 82, 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, 82, 83, 2, 2, 2, 2, 2, 2, 2, 84, - 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 80, 80, 80, 86, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 83, 84, 2, 2, 2, 2, 2, 2, 2, 85, + 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 81, 81, 81, 87, 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, 87, 88, 2, 2, 2, 2, 2, - 2, 2, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2, + 2, 2, 2, 90, 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, 90, 2, 2, 91, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 93, 93, 94, 95, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 94, 94, 95, 96, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, @@ -147,7 +147,7 @@ hb_use_u8[3083] = 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0, 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2, 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22, - 0, 0, 0, 0, 0, 28, 9, 39, 42, 10, 27, 28, 2, 2, 2, 7, + 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7, 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2, 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0, 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0, @@ -191,75 +191,77 @@ hb_use_u8[3083] = 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111, 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28, 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38, - 0, 0, 0, 115, 116, 9, 3, 0, 0, 0, 0, 0, 0, 0, 117, 0, - 0, 0, 0, 0, 0, 0, 4, 118, 119, 40, 40, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119, - 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 5, 121, 0, 0, 0, 0, + 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0, + 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118, + 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, - 122, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29, + 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29, 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 123, 21, 21, 21, 21, 21, 21, 21, 124, 0, 0, 0, 0, + 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, - 50, 2, 2, 2, 20, 20, 125, 114, 0, 2, 2, 2, 126, 18, 57, 18, - 111, 100, 127, 0, 0, 0, 0, 0, 0, 9, 128, 2, 2, 2, 2, 2, - 2, 2, 129, 21, 20, 18, 46, 130, 131, 132, 0, 0, 0, 0, 0, 0, + 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18, + 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2, + 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0, 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57, - 97, 74, 133, 134, 135, 0, 0, 0, 0, 2, 136, 2, 2, 2, 2, 137, - 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 138, 50, 51, 2, 2, - 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 139, 19, - 23, 0, 0, 140, 141, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 142, + 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136, + 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2, + 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19, + 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141, 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0, - 4, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2, + 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2, 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7, - 0, 126, 18, 25, 29, 0, 0, 143, 144, 2, 2, 28, 2, 28, 2, 2, - 2, 2, 2, 2, 0, 12, 35, 0, 145, 2, 2, 11, 35, 0, 28, 2, + 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2, + 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2, 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36, - 0, 2, 2, 2, 114, 114, 114, 114, 114, 146, 2, 7, 0, 0, 0, 0, + 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0, 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2, - 2, 28, 2, 7, 0, 28, 2, 0, 0, 147, 148, 149, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 132, 0, 0, 0, - 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 2, 2, 2, 2, - 2, 51, 50, 51, 0, 0, 0, 0, 151, 9, 72, 2, 2, 2, 2, 2, + 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0, + 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2, + 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2, 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0, - 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 126, 18, 20, 152, - 20, 19, 153, 154, 2, 2, 2, 2, 2, 0, 0, 63, 155, 0, 0, 0, + 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151, + 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0, 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20, - 20, 106, 156, 0, 0, 157, 158, 29, 159, 28, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 160, 42, 0, 0, 0, - 44, 2, 2, 2, 7, 7, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2, - 28, 2, 2, 2, 2, 2, 2, 2, 8, 16, 17, 19, 20, 161, 29, 0, - 0, 9, 9, 28, 2, 2, 2, 7, 28, 7, 2, 28, 2, 2, 56, 15, - 21, 14, 21, 45, 30, 31, 30, 32, 0, 0, 0, 0, 33, 0, 0, 0, - 2, 2, 21, 0, 9, 9, 9, 44, 0, 9, 9, 44, 0, 0, 0, 0, - 0, 2, 2, 63, 23, 18, 18, 18, 20, 21, 124, 13, 15, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 0, 0, 162, 163, 0, 0, 0, 0, 0, 0, - 0, 16, 17, 18, 18, 64, 97, 23, 159, 9, 164, 7, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 63, 23, 18, 18, 0, 46, 46, 9, - 165, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 18, - 0, 21, 17, 18, 18, 19, 14, 80, 165, 36, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 8, 166, 23, 18, 20, 20, 164, 7, 0, 0, - 0, 2, 2, 2, 2, 2, 7, 41, 134, 21, 20, 18, 74, 19, 20, 0, - 0, 2, 2, 2, 7, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 16, - 17, 18, 19, 20, 103, 165, 35, 0, 0, 2, 2, 2, 7, 28, 0, 2, - 2, 2, 2, 28, 7, 2, 2, 2, 2, 21, 21, 16, 30, 31, 10, 167, - 168, 169, 170, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, - 2, 63, 23, 18, 18, 0, 20, 21, 27, 106, 0, 31, 0, 0, 0, 0, - 0, 50, 18, 20, 20, 20, 138, 2, 2, 2, 171, 172, 9, 13, 173, 70, - 174, 0, 0, 1, 145, 0, 0, 0, 0, 50, 18, 20, 14, 17, 18, 2, - 2, 2, 2, 156, 156, 156, 175, 175, 175, 175, 175, 175, 13, 176, 0, 28, - 0, 20, 18, 18, 29, 20, 20, 9, 165, 0, 59, 59, 59, 59, 59, 59, - 59, 64, 19, 80, 44, 0, 0, 0, 0, 2, 2, 2, 7, 2, 28, 2, - 2, 50, 20, 20, 29, 0, 36, 20, 25, 9, 158, 177, 173, 0, 0, 0, - 0, 2, 2, 2, 28, 7, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21, - 45, 20, 33, 80, 66, 0, 0, 0, 0, 2, 178, 64, 45, 0, 0, 0, + 20, 106, 155, 0, 0, 156, 157, 29, 158, 28, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 159, 42, 0, 0, 0, + 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2, + 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2, + 8, 16, 17, 19, 20, 160, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7, + 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32, + 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44, + 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18, + 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, + 161, 162, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23, + 158, 9, 163, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 63, 23, 18, 18, 0, 46, 46, 9, 164, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80, + 164, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 165, + 23, 18, 20, 20, 163, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41, + 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 164, 35, 0, + 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2, + 2, 21, 21, 16, 30, 31, 10, 166, 167, 168, 169, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21, + 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2, + 2, 2, 170, 171, 9, 13, 172, 70, 173, 0, 0, 1, 144, 0, 0, 0, + 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 174, 174, + 174, 174, 174, 174, 13, 175, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9, + 164, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0, + 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20, + 25, 9, 157, 176, 172, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2, + 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0, + 0, 2, 177, 64, 45, 0, 0, 0, 0, 9, 178, 2, 2, 2, 2, 2, + 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0, 0, 179, 179, 179, 106, 7, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0, 56, 180, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56, - 35, 0, 4, 119, 119, 119, 120, 0, 0, 9, 9, 9, 47, 2, 2, 2, + 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, @@ -268,7 +270,7 @@ hb_use_u8[3083] = VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv, CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, - B, O, CS, CS, O, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O, + B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O, CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O, FBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst, VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, @@ -276,18 +278,18 @@ hb_use_u8[3083] = CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv, VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, - FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, CS,VMPst, O,FMAbv, ZWNJ, CGJ, WJ, - WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, - VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, - O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst, - VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, - HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre, - VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, - VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw, - FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, H, H, O, VBlw, + FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, + O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv, + VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, + FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw, + VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, + VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,VMAbv,VMAbv, + H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, IS, + R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw, FBlw,CMAbv, + IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, O, VBlw, }; static const uint16_t -hb_use_u16[768] = +hb_use_u16[776] = { 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, @@ -319,24 +321,25 @@ hb_use_u16[768] = 9, 9,173,170, 0, 0, 0, 0, 0, 0, 0, 9,174,175, 0, 9, 176, 0, 0,177,178, 0, 0, 0,179, 9, 9,180,181,182,183,184, 185, 9, 9,186,187, 0, 0, 0,188, 9,189,190,191, 9, 9,192, - 185, 9, 9,193,194,105,195,102, 9, 33,196,197, 0, 0, 0, 0, - 198,199, 94, 9, 9,200,201, 2,202, 20, 21,203,204,205,206,207, - 9, 9, 9,208,209,210,211, 0,195, 9, 9,212,213, 2, 0, 0, - 9, 9,214,215,216,217, 0, 0, 9, 9, 9,218,219, 2, 0, 0, - 9, 9,220,221, 2, 0, 0, 0, 9,222,223,103,224, 0, 0, 0, - 9, 9,225,226, 0, 0, 0, 0,227,228, 9,229,230, 2, 0, 0, - 0, 0,231, 9, 9,232,233, 0,234, 9, 9,235,236,237, 9, 9, - 238,239, 0, 0, 0, 0, 0, 0, 21, 9,214,240, 7, 9, 70, 18, - 9,241, 73,242, 0, 0, 0, 0,243, 9, 9,244,245, 2,246, 9, - 247,248, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,249, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 98,250, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, 0, 0, 9, 9, 9,251, 0, 0, 0, 0, - 9, 9, 9, 9,252,253,254,254,255,256, 0, 0, 0, 0,257, 0, - 9, 9, 9, 9, 9,258, 0, 0, 9, 9, 9, 9, 9, 9,105, 70, - 94,259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,260, - 9, 9, 70,261,262, 0, 0, 0, 0, 9,263, 0, 9, 9,264, 2, - 9, 9, 9, 9,265, 2, 0, 0,129,129,129,129,129,129,129,129, - 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129, + 185, 9, 9,193,194,105,195,102, 9, 33,196,197,198, 0, 0, 0, + 199,200, 94, 9, 9,201,202, 2,203, 20, 21,204,205,206,207,208, + 9, 9, 9,209,210,211,212, 0,195, 9, 9,213,214, 2, 0, 0, + 9, 9,215,216,217,218, 0, 0, 9, 9, 9,219,220, 2, 0, 0, + 9, 9,221,222, 2, 0, 0, 0, 9,223,224,103,225, 0, 0, 0, + 9, 9,226,227, 0, 0, 0, 0,228,229, 9,230,231, 2, 0, 0, + 0, 0,232, 9, 9,233,234, 0,235, 9, 9,236,237,238, 9, 9, + 239,240, 0, 0, 0, 0, 0, 0, 21, 9,215,241, 7, 9, 70, 18, + 9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9, + 248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250, + 251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 98,254, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 9, 9, 9,255, 0, 0, 0, 0, 9, 9, 9, 9,256,257,258,258, + 259,260, 0, 0, 0, 0,261, 0, 9, 9, 9, 9, 9,262, 0, 0, + 9, 9, 9, 9, 9, 9,105, 70, 94,263, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,264, 9, 9, 70,265,266, 0, 0, 0, + 0, 9,267, 0, 9, 9,268, 2, 9, 9, 9, 9,269, 2, 0, 0, + 129,129,129,129,129,129,129,129,160,160,160,160,160,160,160,160, + 160,160,160,160,160,160,160,129, }; static inline unsigned @@ -347,7 +350,7 @@ hb_use_b4 (const uint8_t* a, unsigned i) static inline uint_fast8_t hb_use_get_category (unsigned u) { - return u<921600u?hb_use_u8[2721+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O; + return u<921600u?hb_use_u8[2753+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O; } #undef B @@ -393,26 +396,5 @@ hb_use_get_category (unsigned u) #undef VMPre -#ifdef HB_USE_TABLE_MAIN -int main (int argc, char **argv) -{ - if (argc != 2) - { - for (unsigned u = 0; u < 0x10FFFFu; u++) - printf ("U+%04X %d\n", u, hb_use_get_category (u)); - return 0; - } - - hb_codepoint_t u; - sscanf (argv[1], "%x", &u); - - printf ("%d\n", hb_use_get_category (u)); - - return 0; -} - -#endif - - #endif /* HB_OT_SHAPER_USE_TABLE_HH */ /* == End of generated table == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc index be4ac813b1..cb4db4a8b2 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc @@ -10,8 +10,8 @@ * # Date: 2015-03-12, 21:17:00 GMT [AG] * # Date: 2019-11-08, 23:22:00 GMT [AG] * - * # Scripts-14.0.0.txt - * # Date: 2021-07-10, 00:35:31 GMT + * # Scripts-15.0.0.txt + * # Date: 2022-04-26, 23:15:02 GMT */ #include "hb.hh" diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper.hh b/thirdparty/harfbuzz/src/hb-ot-shaper.hh index e160987f83..b2d1acb39b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shaper.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper.hh @@ -380,6 +380,10 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner) case HB_SCRIPT_TOTO: case HB_SCRIPT_VITHKUQI: + /* Unicode-15.0 additions */ + case HB_SCRIPT_KAWI: + case HB_SCRIPT_NAG_MUNDARI: + /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. * Otherwise, use the specific shaper. diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc index ceb3bf6df5..1b18270cca 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag.cc +++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc @@ -307,12 +307,12 @@ hb_ot_tags_from_language (const char *lang_str, hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */ - unsigned tag_idx = last_tag_idx.get_relaxed (); + unsigned tag_idx = last_tag_idx; if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) || hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx)) { - last_tag_idx.set_relaxed (tag_idx); + last_tag_idx = tag_idx; unsigned int i; while (tag_idx != 0 && ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language) diff --git a/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh index 5946aef635..f60bc4a3ce 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-avar-table.hh @@ -206,11 +206,10 @@ struct avar v = hb_clamp (v, -(1<<14), +(1<<14)); out.push (v); } - - OT::VariationStore::destroy_cache (var_store_cache); - for (unsigned i = 0; i < coords_length; i++) coords[i] = out[i]; + + OT::VariationStore::destroy_cache (var_store_cache); #endif } diff --git a/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh index 208db46741..420366fbb3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-mvar-table.hh @@ -43,7 +43,7 @@ struct VariationValueRecord public: Tag valueTag; /* Four-byte tag identifying a font-wide measure. */ - HBUINT32 varIdx; /* Outer/inner index into VariationStore item. */ + VarIdx varIdx; /* Outer/inner index into VariationStore item. */ public: DEFINE_SIZE_STATIC (8); diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh index 61b142238e..40a5326118 100644 --- a/thirdparty/harfbuzz/src/hb-repacker.hh +++ b/thirdparty/harfbuzz/src/hb-repacker.hh @@ -276,33 +276,17 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows, return resolution_attempted; } -/* - * Attempts to modify the topological sorting of the provided object graph to - * eliminate offset overflows in the links between objects of the graph. If a - * non-overflowing ordering is found the updated graph is serialized it into the - * provided serialization context. - * - * If necessary the structure of the graph may be modified in ways that do not - * affect the functionality of the graph. For example shared objects may be - * duplicated. - * - * For a detailed writeup describing how the algorithm operates see: - * docs/repacker.md - */ -template<typename T> -inline hb_blob_t* -hb_resolve_overflows (const T& packed, - hb_tag_t table_tag, - unsigned max_rounds = 20, - bool recalculate_extensions = false) { - graph_t sorted_graph (packed); +inline bool +hb_resolve_graph_overflows (hb_tag_t table_tag, + unsigned max_rounds , + bool recalculate_extensions, + graph_t& sorted_graph /* IN/OUT */) +{ sorted_graph.sort_shortest_distance (); bool will_overflow = graph::will_overflow (sorted_graph); if (!will_overflow) - { - return graph::serialize (sorted_graph); - } + return true; graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph); if ((table_tag == HB_OT_TAG_GPOS @@ -314,13 +298,13 @@ hb_resolve_overflows (const T& packed, DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed."); if (!_presplit_subtables_if_needed (ext_context)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed."); - return nullptr; + return false; } DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed."); if (!_promote_extensions_if_needed (ext_context)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed."); - return nullptr; + return false; } } @@ -360,15 +344,41 @@ hb_resolve_overflows (const T& packed, if (sorted_graph.in_error ()) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state."); - return nullptr; + return false; } if (graph::will_overflow (sorted_graph)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); - return nullptr; + return false; } + return true; +} + +/* + * Attempts to modify the topological sorting of the provided object graph to + * eliminate offset overflows in the links between objects of the graph. If a + * non-overflowing ordering is found the updated graph is serialized it into the + * provided serialization context. + * + * If necessary the structure of the graph may be modified in ways that do not + * affect the functionality of the graph. For example shared objects may be + * duplicated. + * + * For a detailed writeup describing how the algorithm operates see: + * docs/repacker.md + */ +template<typename T> +inline hb_blob_t* +hb_resolve_overflows (const T& packed, + hb_tag_t table_tag, + unsigned max_rounds = 20, + bool recalculate_extensions = false) { + graph_t sorted_graph (packed); + if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph)) + return nullptr; + return graph::serialize (sorted_graph); } diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh index cecdcdeb74..f47cde5eb5 100644 --- a/thirdparty/harfbuzz/src/hb-serialize.hh +++ b/thirdparty/harfbuzz/src/hb-serialize.hh @@ -139,6 +139,14 @@ struct hb_serialize_context_t objidx = o.objidx; } #endif + + HB_INTERNAL static int cmp (const void* a, const void* b) + { + int cmp = ((const link_t*)a)->position - ((const link_t*)b)->position; + if (cmp) return cmp; + + return ((const link_t*)a)->objidx - ((const link_t*)b)->objidx; + } }; char *head; @@ -315,7 +323,7 @@ struct hb_serialize_context_t { object_t *obj = current; if (unlikely (!obj)) return; - if (unlikely (in_error())) return; + if (unlikely (in_error() && !only_overflow ())) return; current = current->next; revert (obj->head, obj->tail); diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc index af95615c16..5d4c7cda1b 100644 --- a/thirdparty/harfbuzz/src/hb-static.cc +++ b/thirdparty/harfbuzz/src/hb-static.cc @@ -94,7 +94,7 @@ hb_face_t::load_num_glyphs () const ret = hb_max (ret, load_num_glyphs_from_maxp (this)); - num_glyphs.set_relaxed (ret); + num_glyphs = ret; return ret; } @@ -102,7 +102,7 @@ unsigned int hb_face_t::load_upem () const { unsigned int ret = table.head->get_upem (); - upem.set_relaxed (ret); + upem = ret; return ret; } diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc index 7d19496275..14ae210d49 100644 --- a/thirdparty/harfbuzz/src/hb-subset-input.cc +++ b/thirdparty/harfbuzz/src/hb-subset-input.cc @@ -391,7 +391,7 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input, * * Return value: `true` if success, `false` otherwise * - * Since: REPLACEME + * Since: EXPERIMENTAL **/ hb_bool_t hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, @@ -415,7 +415,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, * * Return value: `true` if success, `false` otherwise * - * Since: REPLACEME + * Since: EXPERIMENTAL **/ hb_bool_t hb_subset_input_pin_axis_location (hb_subset_input_t *input, diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc index 7ff66333a8..079ab8bf99 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.cc +++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc @@ -89,8 +89,6 @@ _remap_indexes (const hb_set_t *indexes, } #ifndef HB_NO_SUBSET_LAYOUT -typedef void (*layout_collect_func_t) (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, const hb_tag_t *languages, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */); - /* * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates. @@ -130,8 +128,8 @@ static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */ template <typename T> static void _collect_layout_indices (hb_subset_plan_t *plan, const T& table, - layout_collect_func_t layout_collect_func, - hb_set_t *indices /* OUT */) + hb_set_t *lookup_indices, /* OUT */ + hb_set_t *feature_indices /* OUT */) { unsigned num_features = table.get_feature_count (); hb_vector_t<hb_tag_t> features; @@ -149,12 +147,23 @@ static void _collect_layout_indices (hb_subset_plan_t *plan, || !plan->check_success (!scripts.in_error ()) || !scripts) return; - layout_collect_func (plan->source, - T::tableTag, - retain_all_scripts ? nullptr : scripts.arrayZ, - nullptr, - retain_all_features ? nullptr : features.arrayZ, - indices); + hb_ot_layout_collect_features (plan->source, + T::tableTag, + retain_all_scripts ? nullptr : scripts.arrayZ, + nullptr, + retain_all_features ? nullptr : features.arrayZ, + feature_indices); + + for (unsigned feature_index : *feature_indices) + { + //TODO: replace HB_OT_LAYOUT_NO_VARIATIONS_INDEX with variation_index for + //instancing + const OT::Feature &f = table.get_feature_variation (feature_index, HB_OT_LAYOUT_NO_VARIATIONS_INDEX); + f.add_lookup_indexes_to (lookup_indices); + } + + //TODO: update for instancing: only collect lookups from feature_indexes that have no variations + table.feature_variation_collect_lookups (feature_indices, lookup_indices); } @@ -232,11 +241,11 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan, { hb_blob_ptr_t<T> table = plan->source_table<T> (); hb_tag_t table_tag = table->tableTag; - hb_set_t lookup_indices; + hb_set_t lookup_indices, feature_indices; _collect_layout_indices<T> (plan, *table, - hb_ot_layout_collect_lookups, - &lookup_indices); + &lookup_indices, + &feature_indices); if (table_tag == HB_OT_TAG_GSUB) hb_ot_layout_lookups_substitute_closure (plan->source, @@ -247,19 +256,13 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan, &lookup_indices); _remap_indexes (&lookup_indices, lookups); - // Collect and prune features - hb_set_t feature_indices; - _collect_layout_indices<T> (plan, - *table, - hb_ot_layout_collect_features, - &feature_indices); - + // prune features table->prune_features (lookups, &feature_indices); hb_map_t duplicate_feature_map; _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map); feature_indices.clear (); - table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices); + table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices); _remap_indexes (&feature_indices, features); table.destroy (); @@ -269,11 +272,46 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan, #ifndef HB_NO_VAR static inline void -_collect_layout_variation_indices (hb_subset_plan_t* plan, - const hb_set_t *glyphset, - const hb_map_t *gpos_lookups, - hb_set_t *layout_variation_indices, - hb_map_t *layout_variation_idx_map) +_generate_varstore_inner_maps (const hb_set_t& varidx_set, + unsigned subtable_count, + hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */) +{ + if (varidx_set.is_empty () || subtable_count == 0) return; + + inner_maps.resize (subtable_count); + for (unsigned idx : varidx_set) + { + uint16_t major = idx >> 16; + uint16_t minor = idx & 0xFFFF; + + if (major >= subtable_count) + continue; + inner_maps[major].add (minor); + } +} + +static inline hb_font_t* +_get_hb_font_with_variations (const hb_subset_plan_t *plan) +{ + hb_font_t *font = hb_font_create (plan->source); + + hb_vector_t<hb_variation_t> vars; + vars.alloc (plan->user_axes_location->get_population ()); + + for (auto _ : *plan->user_axes_location) + { + hb_variation_t var; + var.tag = _.first; + var.value = _.second; + vars.push (var); + } + + hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); + return font; +} + +static inline void +_collect_layout_variation_indices (hb_subset_plan_t* plan) { hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> (); hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> (); @@ -284,13 +322,40 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan, gpos.destroy (); return; } - OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups); + + const OT::VariationStore *var_store = nullptr; + hb_set_t varidx_set; + hb_font_t *font = nullptr; + float *store_cache = nullptr; + bool collect_delta = plan->pinned_at_default ? false : true; + if (collect_delta) + { + font = _get_hb_font_with_variations (plan); + if (gdef->has_var_store ()) + { + var_store = &(gdef->get_var_store ()); + store_cache = var_store->create_cache (); + } + } + + OT::hb_collect_variation_indices_context_t c (&varidx_set, + plan->layout_variation_idx_delta_map, + font, var_store, + plan->_glyphset_gsub, + plan->gpos_lookups, + store_cache); gdef->collect_variation_indices (&c); if (hb_ot_layout_has_positioning (plan->source)) gpos->collect_variation_indices (&c); - gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map); + hb_font_destroy (font); + var_store->destroy_cache (store_cache); + + gdef->remap_layout_variation_indices (&varidx_set, plan->layout_variation_idx_delta_map); + + unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0; + _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps); gdef.destroy (); gpos.destroy (); @@ -506,11 +571,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, #ifndef HB_NO_VAR if (close_over_gdef) - _collect_layout_variation_indices (plan, - plan->_glyphset_gsub, - plan->gpos_lookups, - plan->layout_variation_indices, - plan->layout_variation_idx_map); + _collect_layout_variation_indices (plan); #endif } @@ -585,12 +646,9 @@ _nameid_closure (hb_face_t *face, #ifndef HB_NO_VAR static void -_normalize_axes_location (hb_face_t *face, - const hb_hashmap_t<hb_tag_t, float> *user_axes_location, - hb_hashmap_t<hb_tag_t, int> *normalized_axes_location, /* OUT */ - bool &all_axes_pinned) +_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) { - if (user_axes_location->is_empty ()) + if (plan->user_axes_location->is_empty ()) return; hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes (); @@ -605,25 +663,27 @@ _normalize_axes_location (hb_face_t *face, for (const auto& axis : axes) { hb_tag_t axis_tag = axis.get_axis_tag (); - if (!user_axes_location->has (axis_tag)) + if (!plan->user_axes_location->has (axis_tag)) { axis_not_pinned = true; } else { - int normalized_v = axis.normalize_axis_value (user_axes_location->get (axis_tag)); + int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag)); if (has_avar && axis_count < face->table.avar->get_axis_count ()) { normalized_v = seg_maps->map (normalized_v); } - normalized_axes_location->set (axis_tag, normalized_v); + plan->axes_location->set (axis_tag, normalized_v); + if (normalized_v != 0) + plan->pinned_at_default = false; } if (has_avar) seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps); - + axis_count++; } - all_axes_pinned = !axis_not_pinned; + plan->all_axes_pinned = !axis_not_pinned; } #endif /** @@ -683,8 +743,8 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->gpos_features = hb_map_create (); plan->colrv1_layers = hb_map_create (); plan->colr_palettes = hb_map_create (); - plan->layout_variation_indices = hb_set_create (); - plan->layout_variation_idx_map = hb_map_create (); + plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ()); + plan->gdef_varstore_inner_maps.init (); plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ()); plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ()); @@ -692,12 +752,20 @@ hb_subset_plan_create_or_fail (hb_face_t *face, if (plan->user_axes_location && input->axes_location) *plan->user_axes_location = *input->axes_location; plan->all_axes_pinned = false; + plan->pinned_at_default = true; + + plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ()); + plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ()); if (unlikely (plan->in_error ())) { hb_subset_plan_destroy (plan); return nullptr; } +#ifndef HB_NO_VAR + _normalize_axes_location (face, plan); +#endif + _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan); _populate_gids_to_retain (plan, @@ -725,13 +793,6 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second); } -#ifndef HB_NO_VAR - _normalize_axes_location (face, - input->axes_location, - plan->axes_location, - plan->all_axes_pinned); -#endif - _nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location); if (unlikely (plan->in_error ())) { hb_subset_plan_destroy (plan); @@ -754,44 +815,6 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) { if (!hb_object_destroy (plan)) return; - hb_set_destroy (plan->unicodes); - hb_set_destroy (plan->name_ids); - hb_set_destroy (plan->name_languages); - hb_set_destroy (plan->layout_features); - hb_set_destroy (plan->layout_scripts); - hb_set_destroy (plan->glyphs_requested); - hb_set_destroy (plan->drop_tables); - hb_set_destroy (plan->no_subset_tables); - hb_face_destroy (plan->source); - hb_face_destroy (plan->dest); - hb_map_destroy (plan->codepoint_to_glyph); - hb_map_destroy (plan->glyph_map); - hb_map_destroy (plan->reverse_glyph_map); - hb_map_destroy (plan->glyph_map_gsub); - hb_set_destroy (plan->_glyphset); - hb_set_destroy (plan->_glyphset_gsub); - hb_set_destroy (plan->_glyphset_mathed); - hb_set_destroy (plan->_glyphset_colred); - hb_map_destroy (plan->gsub_lookups); - hb_map_destroy (plan->gpos_lookups); - hb_map_destroy (plan->gsub_features); - hb_map_destroy (plan->gpos_features); - hb_map_destroy (plan->colrv1_layers); - hb_map_destroy (plan->colr_palettes); - hb_set_destroy (plan->layout_variation_indices); - hb_map_destroy (plan->layout_variation_idx_map); - - hb_hashmap_destroy (plan->gsub_langsys); - hb_hashmap_destroy (plan->gpos_langsys); - hb_hashmap_destroy (plan->axes_location); - hb_hashmap_destroy (plan->sanitized_table_cache); - - if (plan->user_axes_location) - { - hb_object_destroy (plan->user_axes_location); - hb_free (plan->user_axes_location); - } - hb_free (plan); } diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh index 8912ae70d5..98a45e5f6d 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.hh +++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh @@ -33,10 +33,56 @@ #include "hb-subset-input.hh" #include "hb-map.hh" +#include "hb-bimap.hh" #include "hb-set.hh" struct hb_subset_plan_t { + hb_subset_plan_t () + {} + + ~hb_subset_plan_t() + { + hb_set_destroy (unicodes); + hb_set_destroy (name_ids); + hb_set_destroy (name_languages); + hb_set_destroy (layout_features); + hb_set_destroy (layout_scripts); + hb_set_destroy (glyphs_requested); + hb_set_destroy (drop_tables); + hb_set_destroy (no_subset_tables); + hb_face_destroy (source); + hb_face_destroy (dest); + hb_map_destroy (codepoint_to_glyph); + hb_map_destroy (glyph_map); + hb_map_destroy (reverse_glyph_map); + hb_map_destroy (glyph_map_gsub); + hb_set_destroy (_glyphset); + hb_set_destroy (_glyphset_gsub); + hb_set_destroy (_glyphset_mathed); + hb_set_destroy (_glyphset_colred); + hb_map_destroy (gsub_lookups); + hb_map_destroy (gpos_lookups); + hb_map_destroy (gsub_features); + hb_map_destroy (gpos_features); + hb_map_destroy (colrv1_layers); + hb_map_destroy (colr_palettes); + + hb_hashmap_destroy (gsub_langsys); + hb_hashmap_destroy (gpos_langsys); + hb_hashmap_destroy (axes_location); + hb_hashmap_destroy (sanitized_table_cache); + hb_hashmap_destroy (hmtx_map); + hb_hashmap_destroy (vmtx_map); + hb_hashmap_destroy (layout_variation_idx_delta_map); + + if (user_axes_location) + { + hb_object_destroy (user_axes_location); + hb_free (user_axes_location); + } + } + hb_object_header_t header; bool successful; @@ -101,10 +147,11 @@ struct hb_subset_plan_t hb_map_t *colrv1_layers; hb_map_t *colr_palettes; - //The set of layout item variation store delta set indices to be retained - hb_set_t *layout_variation_indices; - //Old -> New layout item variation store delta set index mapping - hb_map_t *layout_variation_idx_map; + //Old layout item variation index -> (New varidx, delta) mapping + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map; + + //gdef varstore retained varidx mapping + hb_vector_t<hb_inc_bimap_t> gdef_varstore_inner_maps; hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache; //normalized axes location map @@ -112,6 +159,12 @@ struct hb_subset_plan_t //user specified axes location map hb_hashmap_t<hb_tag_t, float> *user_axes_location; bool all_axes_pinned; + bool pinned_at_default; + + //hmtx metrics map: new gid->(advance, lsb) + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *hmtx_map; + //vmtx metrics map: new gid->(advance, lsb) + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map; public: diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc index f62e7e895b..1a0bcbd1fe 100644 --- a/thirdparty/harfbuzz/src/hb-subset.cc +++ b/thirdparty/harfbuzz/src/hb-subset.cc @@ -406,6 +406,27 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag) } static bool +_dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag, + hb_set_t &visited_set, hb_set_t &revisit_set) +{ + switch (tag) + { + case HB_OT_TAG_hmtx: + case HB_OT_TAG_vmtx: + if (!plan->pinned_at_default && + !visited_set.has (HB_OT_TAG_glyf)) + { + revisit_set.add (tag); + return false; + } + return true; + + default: + return true; + } +} + +static bool _subset_table (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag) @@ -514,7 +535,7 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) return nullptr; } - hb_set_t tags_set; + hb_set_t tags_set, revisit_set; bool success = true; hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); @@ -527,10 +548,27 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) { hb_tag_t tag = table_tags[i]; if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; + if (!_dependencies_satisfied (plan, tag, tags_set, revisit_set)) continue; tags_set.add (tag); success = _subset_table (plan, buf, tag); if (unlikely (!success)) goto end; } + + /*delayed subsetting for some tables since they might have dependency on other tables in some cases: + e.g: during instantiating glyf tables, hmetrics/vmetrics are updated and saved in subset plan, + hmtx/vmtx subsetting need to use these updated metrics values*/ + while (!revisit_set.is_empty ()) + { + hb_set_t revisit_temp; + for (hb_tag_t tag : revisit_set) + { + if (!_dependencies_satisfied (plan, tag, tags_set, revisit_temp)) continue; + tags_set.add (tag); + success = _subset_table (plan, buf, tag); + if (unlikely (!success)) goto end; + } + revisit_set = revisit_temp; + } offset += num_tables; } diff --git a/thirdparty/harfbuzz/src/hb-ucd-table.hh b/thirdparty/harfbuzz/src/hb-ucd-table.hh index 14734c91ea..a372a4afce 100644 --- a/thirdparty/harfbuzz/src/hb-ucd-table.hh +++ b/thirdparty/harfbuzz/src/hb-ucd-table.hh @@ -4,7 +4,7 @@ * * ./gen-ucd-table.py ucd.nounihan.grouped.xml * - * on file with this description: Unicode 14.0.0 + * on file with this description: Unicode 15.0.0 */ #ifndef HB_UCD_TABLE_HH @@ -13,7 +13,7 @@ #include "hb.hh" static const hb_script_t -_hb_ucd_sc_map[163] = +_hb_ucd_sc_map[165] = { HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC, @@ -96,7 +96,8 @@ _hb_ucd_sc_map[163] = HB_SCRIPT_YEZIDI, HB_SCRIPT_CYPRO_MINOAN, HB_SCRIPT_OLD_UYGHUR, HB_SCRIPT_TANGSA, HB_SCRIPT_TOTO, HB_SCRIPT_VITHKUQI, - HB_SCRIPT_MATH, + HB_SCRIPT_MATH, HB_SCRIPT_KAWI, + HB_SCRIPT_NAG_MUNDARI, }; static const uint16_t _hb_ucd_dm1_p0_map[825] = @@ -1068,7 +1069,7 @@ _hb_ucd_dm2_u64_map[388] = #ifndef HB_OPTIMIZE_SIZE static const uint8_t -_hb_ucd_u8[17936] = +_hb_ucd_u8[18260] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14, @@ -1076,7 +1077,7 @@ _hb_ucd_u8[17936] = 25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42, - 7, 7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 7, 7, 43, 7, 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, @@ -1098,12 +1099,12 @@ _hb_ucd_u8[17936] = 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47, 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, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43, @@ -1122,35 +1123,36 @@ _hb_ucd_u8[17936] = 118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131, 132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146, 147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122, - 160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171, - 34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175, - 34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122, + 160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173, + 34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122, + 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177, + 34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122, 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, - 122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122, - 34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186, - 34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189, - 34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122, - 122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195, - 69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209, - 69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122, - 213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216, - 34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122, - 224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232, - 233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34, - 240, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,241, 34, 34, - 34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122, - 34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122, - 34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122, - 245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122, - 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248, - 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249, + 122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122, + 34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188, + 34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122, + 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191, + 34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122, + 122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122, + 122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197, + 69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211, + 69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122, + 215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220, + 34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122, + 228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236, + 237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34, + 244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34, + 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122, + 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122, + 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122, + 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, @@ -1213,7 +1215,7 @@ _hb_ucd_u8[17936] = 44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91, 70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87, 86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61, - 62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36, + 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77, 44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36, 57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36, @@ -1223,7 +1225,7 @@ _hb_ucd_u8[17936] = 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36, 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44, - 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36, + 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36, 77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67, 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, @@ -1390,18 +1392,19 @@ _hb_ucd_u8[17936] = 44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44, 16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44, - 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44, - 180, 27, 30, 2, 2, 44, 44, 44, 36, 43, 43, 2, 2, 44, 44, 44, - 36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44, - 27, 27, 27, 7, 7, 7, 7, 7, 71, 70, 71, 44, 44, 44, 44, 57, - 86, 87, 43, 85, 87, 60,185, 2, 2, 80, 44, 44, 44, 44, 79, 44, - 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43, - 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 94, 98, 44, 44, 44, 44, - 36, 70, 2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85, - 98, 36, 63, 2, 59, 43, 60, 87, 7, 7, 7, 7, 7, 63, 63, 2, - 179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43, 2, 2, 2, 80, + 36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43, + 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44, + 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44, + 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, + 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7, + 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2, + 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7, + 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44, + 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87, + 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27, + 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87, + 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70, 86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62, @@ -1423,17 +1426,20 @@ _hb_ucd_u8[17936] = 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60, 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2, - 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87, - 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36, - 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43, - 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36, - 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44, - 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90, - 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44, + 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44, + 43, 43, 43, 80, 43, 43, 43, 87, 63, 2, 2, 44, 44, 44, 44, 44, + 2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44, + 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57, + 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36, + 36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44, + 36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36, + 36, 36, 86, 43, 43, 80, 44, 86, 85, 60, 2, 2, 2, 2, 2, 2, 27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181, 2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44, - 65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44, + 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43, + 43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44, 7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44, @@ -1441,7 +1447,8 @@ _hb_ucd_u8[17936] = 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44, 86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81, - 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, + 36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44, + 36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44, 67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86, @@ -1466,10 +1473,12 @@ _hb_ucd_u8[17936] = 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67, 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43, 16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110, - 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43, - 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44, - 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80, - 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 96, + 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43, + 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44, + 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57, + 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77, + 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43, + 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43, 36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27, 16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27, 188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163, @@ -1482,138 +1491,141 @@ _hb_ucd_u8[17936] = 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67, - 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44, + 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67, + 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, + 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44, - 65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44, - 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21, - 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, - 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, - 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, - 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, - 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, - 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11, - 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12, - 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26, - 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, - 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6, - 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26, - 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15, - 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21, - 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24, - 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28, - 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, - 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5, - 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, - 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, - 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, - 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, - 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15, - 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1, - 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, - 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 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, 17, 18, 19, 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, 20, - 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 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, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0, + 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, + 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, + 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, + 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, + 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5, + 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2, + 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26, + 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21, + 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, + 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1, + 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12, + 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7, + 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22, + 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6, + 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1, + 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, + 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2, + 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, + 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, + 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6, + 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, + 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, + 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, + 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, + 15, 0, 16, 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, - 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, - 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 6, 7, 8, 0, 9, 0, 10, 11, 0, 0, 12, 13, - 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 0, 21, 0, 22, 23, - 0, 24, 25, 0, 0, 24, 26, 27, 0, 24, 26, 0, 0, 24, 26, 0, - 0, 24, 26, 0, 0, 0, 26, 0, 0, 24, 28, 0, 0, 24, 26, 0, - 0, 29, 26, 0, 0, 0, 30, 0, 0, 31, 32, 0, 0, 33, 34, 0, - 35, 36, 0, 37, 38, 0, 39, 0, 0, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 43, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0, - 0, 47, 0, 0, 0, 0, 0, 0, 48, 0, 0, 49, 0, 50, 51, 0, - 0, 52, 53, 54, 0, 55, 0, 56, 0, 57, 0, 0, 0, 0, 58, 59, - 0, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 62, 63, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, - 0, 0, 0, 65, 0, 0, 0, 66, 0, 67, 0, 0, 68, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 71, - 0, 0, 0, 0, 0, 0, 0, 0, 72, 73, 0, 0, 0, 0, 53, 74, - 0, 75, 76, 0, 0, 77, 78, 0, 0, 0, 0, 0, 0, 79, 80, 81, - 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, - 82, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 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, 84, 0, 0, 0, 0, 0, 0, 0, 85, - 0, 0, 0, 86, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 89, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, + 0, 36, 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, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, - 0, 0, 92, 0, 93, 0, 0, 0, 0, 0, 72, 94, 0, 95, 0, 0, - 96, 97, 0, 77, 0, 0, 98, 0, 0, 99, 0, 0, 0, 0, 0,100, - 0,101, 26,102, 0, 0, 0, 0, 0, 0,103, 0, 0, 0,104, 0, - 0, 0, 0, 0, 0, 65,105, 0, 0, 65, 0, 0, 0,106, 0, 0, - 0,107, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, - 0,108,109, 0, 0, 0, 0, 78, 0, 44,110, 0,111, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, - 0, 0,112, 0,113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,114, - 0,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0,117, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,118,119,120, 0, 0, 0, 0,121, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,122,123, 0, 0, 0, 0, 0, 0, - 0,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0,125, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, - 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, - 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 0, 0, 0, 0, - 19, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 1, - 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, - 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 38, 1, 39, - 14, 39, 40, 41, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, - 0, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 0, 0, - 0, 0, 19, 1, 21, 0, 0, 47, 0, 0, 0, 0, 0, 38, 48, 1, - 1, 49, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, - 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, - 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 55, - 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 56, 0, 60, 0, 0, - 0, 0, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 69, 70, 0, - 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 0, 0, 0, - 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0, - 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, - 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, - 0, 0, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 19, 84, 0, - 62, 0, 0, 0, 0, 49, 1, 85, 0, 0, 0, 0, 1, 52, 15, 86, - 36, 10, 21, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, - 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, - 0, 0, 88, 0, 0, 0, 0, 0, 0, 89, 0, 0, 88, 0, 0, 0, - 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 87, 9, 12, 4, - 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, - 1, 1, 1, 1, 1, 94, 95, 96, 0, 0, 0, 0, 97, 1, 98, 58, - 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 61, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103, 0, - 0, 0, 0, 19, 0, 1, 1, 50, 0, 0, 0, 0, 0, 0, 0, 38, - 0, 0, 0, 0, 50, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 62, 0, 0, 0, 0, 1, 1, 1, 1, 50, 0, 0, 0, - 0, 0,104, 68, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, - 0, 0, 0, 0, 78, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0,107, - 1, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, - 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 87, 0, - 0, 0, 0,108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,109, 61, - 0,110, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 19, 58, 0, 0, 0, 0, 0,111, 14, 52, 84, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, + 9, 0, 10, 11, 0, 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, + 18, 19, 20, 0, 21, 0, 22, 23, 0, 24, 25, 0, 0, 24, 26, 27, + 0, 24, 26, 0, 0, 24, 26, 0, 0, 24, 26, 0, 0, 0, 26, 0, + 0, 24, 28, 0, 0, 24, 26, 0, 0, 29, 26, 0, 0, 0, 30, 0, + 0, 31, 32, 0, 0, 33, 34, 0, 35, 36, 0, 37, 38, 0, 39, 0, + 0, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, 45, 0, + 0, 0, 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, + 48, 0, 0, 49, 0, 50, 51, 0, 0, 52, 53, 54, 0, 55, 0, 56, + 0, 57, 0, 0, 0, 0, 58, 59, 0, 0, 0, 0, 0, 0, 60, 61, + 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, + 0, 67, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 70, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 73, 0, 0, 0, 0, 53, 74, 0, 75, 76, 0, 0, 77, 78, 0, + 0, 0, 0, 0, 0, 79, 80, 81, 0, 0, 0, 0, 0, 0, 0, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 83, 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, 84, + 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 86, 0, 0, 0, 0, + 87, 88, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 91, 0, 92, 0, 0, 93, 0, 94, 0, 0, 0, + 0, 0, 72, 95, 0, 96, 0, 0, 97, 98, 0, 77, 0, 0, 99, 0, + 0,100, 0, 0, 0, 0, 0,101, 0,102, 26,103, 0, 0, 0, 0, + 0, 0,104, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 65,106, 0, + 0, 65, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0, 0, 0, 0, + 0, 96, 0, 0, 0, 0, 0, 0, 0,109,110, 0, 0, 0, 0, 78, + 0, 44,111, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 65, 0, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,116, 0,117, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, + 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,121,122, 0, 0, + 0, 0,123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 124,125, 0, 0,126, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,127, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,129, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,130, 0, 0, 0,131, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, + 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, + 18, 1, 1, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, + 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 31, 0, + 0, 0, 32, 33, 34, 35, 1, 36, 0, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 43, 36, 44, 45, + 21, 45, 46, 0, 0, 0, 0, 0, 0, 0, 19, 1, 21, 0, 0, 47, + 0, 0, 0, 0, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 52, 1, + 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, + 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, + 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, + 0, 0, 0, 56, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, + 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, + 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, + 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, + 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, 71, 72, 73, 74, + 75, 76, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 80, 0, 0, + 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 63, 0, 0, 81, + 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, + 0, 0, 0, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, + 0, 0, 0, 0, 1, 52, 15, 86, 36, 10, 21, 87, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, + 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, + 0, 89, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, + 0, 0, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, + 21, 1, 21, 92, 93, 1, 1, 1, 1, 1, 1, 1, 1, 94, 95, 96, + 0, 0, 0, 0, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0, + 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,101,102, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 19, 0, 1, 1, 50, + 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 50, 0, 0, 0, + 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, + 1, 1, 1, 1, 50, 0, 0, 0, 0, 0,104, 68, 0, 0, 0, 0, + 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, + 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 58, 38, + 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 47, 84, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,109, 61, 0,110, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 19, 58, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 51, 0,111, 14, 52, 84, 0, 0, 0, 112, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 61, 0, 0, 0, 0, 0, 0,113, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0, 0, 0, 0, @@ -1624,89 +1636,90 @@ _hb_ucd_u8[17936] = 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 78, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 8, 91, 0, 0, - 0, 0, 0, 0, 1, 87, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4, - 122, 49, 23, 0, 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0, - 38, 58, 0, 0, 0, 0, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, - 48,105, 87, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4,122, 0, 0, - 0, 1,123, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230, - 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220, - 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220, - 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0, - 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233, - 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230, - 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0, - 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, - 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0, - 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0, - 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230, - 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230, - 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220, - 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230, - 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, - 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107, - 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220, - 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130, - 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, - 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, - 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220, - 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0, - 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230, - 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1, - 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228, - 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230, - 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, - 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, - 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, - 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0, - 220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, - 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, - 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 0, 0, 0, 0, 0, 61, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 91, 0, 0, 0, 0, 0, 0, 1, 87, 0, 0, + 0, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, + 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 0, 0, + 0, 0, 38, 50, 0, 0, 0, 0, 38, 58, 0, 0, 0, 0, 0, 0, + 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,123, 0, 0, 0, 0, + 0, 0, 0, 0, 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0, + 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216, + 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220, + 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220, + 220,220,230,230,230,220,220, 0,230,230,230,220,220,220,220,230, + 232,220,220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230, + 0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220, + 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, + 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, + 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230, + 220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230, + 230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230, + 220,220,230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0, + 230,230, 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220, + 230,220,220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0, + 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, + 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0, + 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122, + 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0, + 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, + 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, + 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220, + 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0, + 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0, + 230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230, + 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230, + 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, + 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, + 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, + 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, + 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, + 0,226,216,216,216,216,216, 0,220,220,220, 0,232,232,220,230, + 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19, + 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, - 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, - 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, - 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, - 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, - 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, - 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, - 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, - 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, - 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, - 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, - 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, - 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, - 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, - 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, - 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, - 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, - 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, + 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28, + 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, + 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, + 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12, + 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19, + 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8, + 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27, + 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0, + 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20, + 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20, + 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20, + 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0, + 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0, + 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45, + 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1, + 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, + 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13, + 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, - 7, 7, 43, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7, + 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, @@ -1727,411 +1740,419 @@ _hb_ucd_u8[17936] = 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 44, 0, 0, 1, 2, 2, 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, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, - 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, - 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1, + 2, 2, 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, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56, + 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61, + 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, - 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,102,103,104,105, - 106,107,108,109,110,111, 96,112,113,114,115,116,117,118,119,119, - 120,121,122,123,124,125,126,127,128,129,130,131,132, 96,133,134, - 135,136,137,138,139,140,141,142,143, 96,144,145, 96,146,147,148, - 149, 96,150,151,152,153,154,155, 96, 96,156,157,158,159, 96,160, - 96,161,162,162,162,162,162,162,162,163,164,162,165, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96,166,167,167,167,167,167,167,167,167,168, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96, - 96, 96,171,171,171,171,172,173,174,175, 96, 96, 96, 96,176,177, - 178,179,180,180,180,180,180,180,180,180,180,180,180,180,180,180, - 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, - 180,181,180,180,180,180,180,180,182,182,182,183,184, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96,185,186,187,188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 193,194, 59,195,196,197,198,199,200, 96,201,202,203, 59, 59,204, - 59,205,206,206,206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96, - 208, 96,209, 96,210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96, - 96,212,213,214,215, 96, 96, 96, 96, 96,216,217,218, 96,219,220, - 96, 96,221,222, 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225, - 226,227,228,229, 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96, - 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233, + 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109, + 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123, + 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138, + 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151, + 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164, + 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169, + 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173, + 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,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,183,182,182, + 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189, + 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197, + 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208, + 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212, + 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218, + 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226, + 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233, + 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 234, 70,235, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236, - 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96, - 96, 96, 70, 70, 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 70, 70, 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96, - 96, 96,240, 96,241,242, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, - 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, - 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, - 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, - 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, - 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, - 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, - 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, - 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, - 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, - 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, - 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, - 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, - 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, - 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, - 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, - 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, - 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, - 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, - 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, - 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, - 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, - 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, - 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, - 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, - 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, - 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, - 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, - 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, - 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, - 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, - 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, - 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, - 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, - 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, - 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, - 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, - 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, - 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, - 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, - 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, - 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, - 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, - 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, - 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, - 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, - 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, - 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, - 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, - 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, - 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, - 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, - 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, - 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, - 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, - 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, - 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, - 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, - 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, - 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, - 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, - 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, - 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, - 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, - 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, - 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, - 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, - 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, - 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, - 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, - 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, - 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, - 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, - 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, - 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, - 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, - 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, - 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, - 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, - 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, - 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, - 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, - 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, - 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, - 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, - 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, - 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, - 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, - 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, - 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, - 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, - 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, - 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70, + 70, 70, 70, 70, 70,241, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, + 70, 70,242, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, + 70, 70, 70, 70,243, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70,244, 96, 96, 96, 96, 96, 96, 96, 96,245, 96, + 246,247, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, + 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, + 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, + 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, + 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, + 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, + 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, + 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, + 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, + 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5, + 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, + 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, + 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, + 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2, + 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5, + 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11, + 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, + 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, + 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11, + 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2, + 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10, + 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, + 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, + 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, + 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2, + 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, + 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21, + 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, + 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, + 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, + 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, + 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, + 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, + 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, + 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, + 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, + 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, + 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23, + 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, + 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, + 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16, + 16, 16, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2, + 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36, + 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, + 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, + 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, + 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18, + 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, + 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, + 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, + 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, + 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, + 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, + 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, + 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, + 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, + 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, + 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, + 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, + 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, + 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, + 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62, + 62, 62, 62, 62, 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, + 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, + 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, + 73, 73, 73, 73, 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8, + 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, + 19, 19, 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 19, 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, + 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, + 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, + 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, + 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, + 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, + 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, + 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, + 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, - 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, - 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, - 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, - 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, - 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, - 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, - 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2, - 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2, - 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, - 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, - 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, - 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, - 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, - 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, - 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, - 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, - 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, - 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, - 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, - 0, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, - 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, - 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, - 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, - 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, - 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, - 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, - 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118,118,118,118,118, - 118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, - 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, - 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, - 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135,135,135,135,135, - 135,135,135,135,135,135, 2, 2, 2, 2,106,106,106,106,106,106, - 106,106,104,104,104,104,104,104,104,104,104,104,104,104, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161,161,161,161,161, - 161,161,161,161,161, 2,161,161,161,161,161,161,161, 2,161,161, - 2,161,161,161, 2,161,161,161,161,161,161,161, 2,161,161, 2, - 2, 2,110,110,110,110,110,110,110,110,110,110,110,110,110,110, - 110, 2,110,110,110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, - 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47, - 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, - 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 2, 81,120,120,120,120,120,120,120,120,116,116,116,116,116,116, - 116,116,116,116,116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, - 2,116,128,128,128,128,128,128,128,128,128,128,128, 2,128,128, - 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, - 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, - 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, - 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, - 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, - 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, - 88, 88,117,117,117,117,117,117,117,117,112,112,112,112,112,112, - 112,112,112,112,112,112,112,112,112, 2, 2, 2, 2,112,112,112, - 112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122,122,122,122,122, - 122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, - 2, 2, 2,122,122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130, - 130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130, - 130,130,144,144,144,144,144,144,144,144,144,144, 2, 2, 2, 2, - 2, 2,156,156,156,156,156,156,156,156,156,156, 2,156,156,156, - 2, 2,156,156, 2, 2, 2, 2, 2, 2,147,147,147,147,147,147, - 147,147,148,148,148,148,148,148,148,148,148,148, 2, 2, 2, 2, - 2, 2,158,158,158,158,158,158,158,158,158,158, 2, 2, 2, 2, - 2, 2,153,153,153,153,153,153,153,153,153,153,153,153, 2, 2, - 2, 2,149,149,149,149,149,149,149,149,149,149,149,149,149,149, - 149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, - 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,101,101,101,101, - 101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, - 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, - 96, 96,111,111,111,111,111,111,111,111,111,111,111,111,111,111, - 111, 2,100,100,100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108,108,108,108,108, - 108,108,108,108, 2,108,108,108,108,108,108,108,108,108,108,108, - 108, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129, - 2,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, - 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109,109,109,109,109, - 109,109,109,109,109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, - 2, 2,107,107,107,107, 2,107,107,107,107,107,107,107,107, 2, - 2,107,107, 2, 2,107,107,107,107,107,107,107,107,107,107,107, - 107,107,107, 2,107,107,107,107,107,107,107, 2,107,107, 2,107, - 107,107,107,107, 2, 1,107,107,107,107,107, 2, 2,107,107,107, - 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107, - 107,107,107,107,107,107, 2, 2,107,107,107,107,107,107,107, 2, - 2, 2,137,137,137,137,137,137,137,137,137,137,137,137, 2,137, - 137,137,137,137, 2, 2, 2, 2, 2, 2,124,124,124,124,124,124, - 124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,123,123,123,123, - 123,123,123,123,123,123,123,123, 2, 2,114,114,114,114,114,114, - 114,114,114,114,114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, - 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102,102,102,102,102, - 102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,126,126,126,126, - 126,126,126,126,126, 2, 2,126,126,126,126,126,126,126, 2, 2, - 2, 2,126,126,126,126,126,126,126, 2,142,142,142,142,142,142, - 142,142,142,142,142,142, 2, 2, 2, 2,125,125,125,125,125,125, - 125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2,125,154,154,154,154,154,154,154, 2, 2,154, 2, 2,154,154, - 154,154,154,154,154,154, 2,154,154, 2,154,154,154,154,154,154, - 154,154,154,154,154,154,154,154, 2,154,154, 2, 2,154,154,154, - 154,154,154,154, 2, 2, 2, 2, 2, 2,150,150,150,150,150,150, - 150,150, 2, 2,150,150,150,150,150,150,150,150,150,150,150, 2, - 2, 2,141,141,141,141,141,141,141,141,140,140,140,140,140,140, - 140,140,140,140,140, 2, 2, 2, 2, 2,121,121,121,121,121,121, - 121,121,121, 2, 2, 2, 2, 2, 2, 2,133,133,133,133,133,133, - 133,133,133, 2,133,133,133,133,133,133,133,133,133,133,133,133, - 133, 2,133,133,133,133,133,133, 2, 2,133,133,133,133,133, 2, - 2, 2,134,134,134,134,134,134,134,134, 2, 2,134,134,134,134, - 134,134, 2,134,134,134,134,134,134,134,134,134,134,134,134,134, - 134, 2,138,138,138,138,138,138,138, 2,138,138, 2,138,138,138, - 138,138,138,138,138,138,138,138,138,138, 2, 2,138, 2,138,138, - 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, - 2,143,143, 2,143,143,143,143,143,143,143,143,143,143,143,143, - 143,143,143,143,143,143,143,143,143, 2,143,143, 2,143,143,143, - 143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, - 2, 2,145,145,145,145,145,145,145,145,145, 2, 2, 2, 2, 2, - 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, - 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, - 2, 2,157,157,157,157,157,157,157,157,157,157,157, 2, 2, 2, - 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 2, 80, 2, 2, 2, 2, 2, 2, 2,127,127,127,127,127,127, - 127,127,127,127,127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, - 2, 2,115,115,115,115,115,115,115,115,115,115,115,115,115,115, - 115, 2,115,115, 2, 2, 2, 2,115,115,159,159,159,159,159,159, - 159,159,159,159,159,159,159,159,159, 2,159,159, 2, 2, 2, 2, - 2, 2,103,103,103,103,103,103,103,103,103,103,103,103,103,103, - 2, 2,119,119,119,119,119,119,119,119,119,119,119,119,119,119, - 2, 2,119,119, 2,119,119,119,119,119, 2, 2, 2, 2, 2,119, - 119,119,146,146,146,146,146,146,146,146,146,146,146, 2, 2, 2, - 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, - 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, - 2, 2,136,136,136,136,136,136,136,136,155,155,155,155,155,155, - 155,155,155,155,155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, - 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, - 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, - 2, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, - 17, 17,139,139,139,139,139,139,139,139,139,139,139,139, 2, 2, - 2, 2,105,105,105,105,105,105,105,105,105,105,105, 2, 2, 2, - 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, - 2, 2,105,105, 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131,131,131, - 131,131,131,131,131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131, - 131,131, 2,131,131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, - 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, - 56, 56, 56, 56, 56, 2, 2, 2, 2, 2,151,151,151,151,151,151, - 151,151,151,151,151,151,151, 2, 2, 2,151,151,151,151,151,151, - 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,160,160,160,160, - 160,160,160,160,160,160,160,160,160, 2,152,152,152,152,152,152, - 152,152,152,152, 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 2, 30, - 30, 2,113,113,113,113,113,113,113,113,113,113,113,113,113, 2, - 2,113,113,113,113,113,113,113,113, 2,132,132,132,132,132,132, - 132,132,132,132,132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2, - 132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, - 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, - 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, - 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, - 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, - 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 13, 2, 2, 2, 2, 2, - 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, - 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, - 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, + 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, + 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, + 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, + 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, + 19, 2, 2, 2, 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19, + 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, + 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, + 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, + 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, + 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, + 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, + 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, + 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, + 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, + 0, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, + 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, + 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, + 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, + 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118, + 118,118,118,118,118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, + 59, 59, 59, 59, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, + 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135, + 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,106,106, + 106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104, + 104,104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,161,161, + 161,161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161, + 161, 2,161,161, 2,161,161,161, 2,161,161,161,161,161,161,161, + 2,161,161, 2, 2, 2,110,110,110,110,110,110,110,110,110,110, + 110,110,110,110,110, 2,110,110,110,110,110,110, 2, 2, 19, 19, + 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, 47, + 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, + 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 2, 81,120,120,120,120,120,120,120,120,116,116, + 116,116,116,116,116,116,116,116,116,116,116,116,116, 2, 2, 2, + 2, 2, 2, 2, 2,116,128,128,128,128,128,128,128,128,128,128, + 128, 2,128,128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98, + 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, + 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 57, 57, + 57, 57, 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, + 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, + 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, + 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,112,112, + 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, + 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2,122,122, + 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122, + 122,122,122, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130, + 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, + 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144, + 2, 2, 2, 2, 2, 2,156,156,156,156,156,156,156,156,156,156, + 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 3, 3,147,147,147,147,147,147,147,147,148,148, + 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158, + 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153, + 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149, + 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, + 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2, + 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111, 2,100,100, + 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108, + 2,108,108,108,108,108,108,108, 2, 2, 2, 2, 2, 2,129,129, + 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129, + 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129, + 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, + 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107, + 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2, + 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2, + 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107, + 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2, + 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107, + 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137, + 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137, + 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, + 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123, + 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114, + 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32, + 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, + 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126, + 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126,126, + 126,126,126,126,126, 2,142,142,142,142,142,142,142,142,142,142, + 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125, + 125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,154,154, + 154,154,154,154,154, 2, 2,154, 2, 2,154,154,154,154,154,154, + 154,154, 2,154,154, 2,154,154,154,154,154,154,154,154,154,154, + 154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154,154, + 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2, + 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141, + 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140, + 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2, + 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2,133,133, + 133,133,133,133,133,133,133, 2,133,133,133,133,133,133,133,133, + 133,133,133,133,133, 2,133,133,133,133,133,133, 2, 2,133,133, + 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134, 2, 2, + 134,134,134,134,134,134, 2,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138, + 2,138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, + 138, 2,138,138, 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143, + 143,143,143,143, 2,143,143, 2,143,143,143,143,143,143,143,143, + 143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143,143, + 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, + 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145, 2, + 2, 2, 2, 2, 2, 2,163,163,163,163,163,163,163,163,163, 2, + 163,163,163,163,163,163,163,163,163, 2, 2, 2,163,163,163,163, + 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, + 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, + 63, 63, 2, 2, 2, 2,157,157,157,157,157,157,157,157,157,157, + 157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 2, 2,127,127,127,127,127,127,127,127,127,127, + 127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115, + 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115, + 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159, + 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103, + 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119, + 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146, + 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, + 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136, + 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155, + 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 17, + 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15, + 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2, + 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, 2, + 2, 2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139, + 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, + 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 1, 1, + 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131, + 131,131,131,131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 2, + 2,131,131,131,131,131, 2,131,131,131,131,131,131,131, 2, 2, + 2, 2, 2, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2, + 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56, + 56, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 6,151,151,151,151,151,151,151,151,151,151, + 151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151, + 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160, + 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152, + 2, 2, 2, 2, 2,152,164,164,164,164,164,164,164,164,164,164, + 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 2, 30, 30, 2,113,113, + 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, + 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132, + 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3, + 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 13, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 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, 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, 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, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, + 20, 9, 21, 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, 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, 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, 22, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -2140,60 +2161,61 @@ _hb_ucd_u8[17936] = 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, 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, 9, 9, 9, 9, 23, 24, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, - 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 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, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, - 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, + 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, + 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 41, 42, 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, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, - 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, + 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, + 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, + 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, + 0, 0, 0, 0, 0, 0, 66, 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, - 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0, - 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, - 0, 0,116, 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,117, 0, 0, + 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0, + 107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, + 0, 0,115, 0, 0, 0,116, 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,118,119,120,121, 0,122,123,124,125,126, 0,127, + 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124, + 125,126, 0,127, 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,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, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, + 0, 0, 0, 0, 0, 0,164, 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, - 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, 0, 0, - 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, - 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,168, 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,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171, + 172, 0, 0, 0,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, 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,169,170, 0, 0, 0, 0,171,172, 0, 0, 0, - 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, 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, 1, 2, 3, 4, + 1, 2, 3, 4, }; static const uint16_t -_hb_ucd_u16[9200] = +_hb_ucd_u16[9320] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -2267,509 +2289,517 @@ _hb_ucd_u16[9200] = 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140, 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474, 48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476, - 48, 48, 477, 478, 140, 140, 140, 140, 48, 464, 479, 48, 62, 480, 140, 48, - 481, 140, 140, 48, 482, 140, 48, 314, 483, 48, 48, 484, 485, 457, 486, 487, - 222, 48, 48, 488, 489, 48, 196, 192, 490, 48, 491, 492, 493, 48, 48, 494, - 222, 48, 48, 495, 496, 497, 498, 499, 48, 97, 500, 501, 140, 140, 140, 140, - 502, 503, 504, 48, 48, 505, 506, 192, 507, 83, 84, 508, 509, 510, 511, 512, - 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140, - 48, 48, 518, 519, 520, 521, 140, 140, 48, 48, 48, 522, 523, 192, 524, 140, - 48, 48, 525, 526, 192, 140, 140, 140, 48, 173, 527, 528, 314, 140, 140, 140, - 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530, - 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140, - 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196, - 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140, - 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 48, 557, 140, 140, 140, 100, 271, 558, 559, 560, - 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562, - 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563, - 48, 48, 200, 564, 140, 140, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140, - 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565, - 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578, + 48, 48, 477, 478, 140, 140, 140, 479, 48, 464, 480, 48, 62, 481, 140, 48, + 482, 140, 140, 48, 483, 140, 48, 314, 484, 48, 48, 485, 486, 457, 487, 488, + 222, 48, 48, 489, 490, 48, 196, 192, 491, 48, 492, 493, 494, 48, 48, 495, + 222, 48, 48, 496, 497, 498, 499, 500, 48, 97, 501, 502, 503, 140, 140, 140, + 504, 505, 506, 48, 48, 507, 508, 192, 509, 83, 84, 510, 511, 512, 513, 514, + 48, 48, 48, 515, 516, 517, 478, 140, 48, 48, 48, 518, 519, 192, 140, 140, + 48, 48, 520, 521, 522, 523, 140, 140, 48, 48, 48, 524, 525, 192, 526, 140, + 48, 48, 527, 528, 192, 140, 140, 140, 48, 173, 529, 530, 314, 140, 140, 140, + 48, 48, 501, 531, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 532, + 533, 534, 48, 535, 536, 192, 140, 140, 140, 140, 537, 48, 48, 538, 539, 140, + 540, 48, 48, 541, 542, 543, 48, 48, 544, 545, 546, 48, 48, 48, 48, 196, + 547, 140, 140, 140, 140, 140, 140, 140, 84, 48, 520, 548, 549, 148, 175, 550, + 48, 551, 552, 553, 140, 140, 140, 140, 554, 48, 48, 555, 556, 192, 557, 48, + 558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 560, + 561, 115, 48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566, + 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568, + 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 569, + 48, 48, 48, 570, 571, 572, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140, + 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 573, + 48, 48, 48, 574, 575, 576, 577, 578, 48, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 9, 9, 11, 11, 271, 579, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586, 48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140, - 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579, - 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 206, - 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140, - 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588, - 589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461, - 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11, - 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11, - 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613, - 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622, - 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140, - 628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140, - 48, 48, 151, 633, 634, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637, - 140, 140, 140, 140, 140, 140, 638, 200, 48, 48, 48, 48, 639, 585, 140, 140, - 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498, - 271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140, - 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654, - 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324, - 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209, - 659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662, - 209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323, - 209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209, - 664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665, - 287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192, - 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 196, 48, 48, 48, 48, + 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587, + 48, 48, 588, 589, 140, 590, 591, 48, 48, 48, 48, 48, 48, 48, 48, 206, + 48, 48, 48, 48, 48, 48, 71, 151, 196, 592, 593, 140, 140, 140, 140, 140, + 32, 32, 594, 32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598, + 599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140, + 140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461, + 9, 603, 11, 604, 605, 606, 241, 9, 607, 608, 609, 610, 611, 9, 603, 11, + 612, 613, 11, 614, 615, 616, 617, 9, 618, 11, 9, 603, 11, 604, 605, 11, + 241, 9, 607, 617, 9, 618, 11, 9, 603, 11, 619, 9, 620, 621, 622, 623, + 11, 624, 9, 625, 626, 627, 628, 11, 629, 9, 630, 11, 631, 632, 632, 632, + 32, 32, 32, 633, 32, 32, 634, 635, 636, 637, 45, 140, 140, 140, 140, 140, + 638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643, 27, 27, 27, 644, 140, + 645, 140, 140, 140, 140, 140, 140, 140, 48, 48, 151, 646, 647, 140, 140, 140, + 140, 48, 648, 140, 48, 48, 649, 650, 140, 140, 140, 140, 140, 48, 651, 192, + 140, 140, 140, 140, 140, 140, 652, 200, 48, 48, 48, 48, 653, 595, 140, 140, + 9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499, + 271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140, + 659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668, + 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324, + 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209, + 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676, + 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678, + 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209, + 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426, + 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192, + 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, - 391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, - 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11, - 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21, - 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26, - 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31, - 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31, - 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43, - 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31, - 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53, - 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67, - 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26, - 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91, - 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26, - 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112, - 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113, - 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26, - 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131, - 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26, - 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26, - 150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156, 26, 26, 26, 26, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157, - 157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162, 26, 26, 26, 26, - 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, - 163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169, - 169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169, - 169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173, - 169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176, - 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, - 178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182, - 183, 183, 184, 185, 186, 186, 187, 26, 188, 188, 189, 26, 190, 191, 192, 26, - 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195, - 196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199, - 197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201, 26, - 202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208, 26, - 209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193, - 213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217, - 215, 218, 215, 218, 215, 219, 9, 9, 9, 220, 26, 26, 26, 26, 26, 26, - 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223, - 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227, - 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231, - 18, 232, 164, 164, 164, 164, 164, 233, 224, 26, 234, 9, 235, 236, 237, 238, - 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244, - 2, 2, 2, 2, 2, 2, 2, 245, 9, 9, 9, 9, 9, 9, 9, 9, - 14, 14, 246, 246, 14, 14, 14, 14, 246, 246, 14, 247, 14, 14, 14, 246, - 14, 14, 14, 14, 14, 14, 248, 14, 248, 14, 249, 250, 14, 14, 251, 252, - 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 255, 256, - 0, 257, 2, 258, 0, 0, 0, 0, 259, 26, 9, 9, 9, 9, 260, 26, - 0, 0, 0, 0, 261, 262, 4, 0, 0, 263, 0, 0, 2, 2, 2, 2, - 2, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140, + 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684, + 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4, + 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, + 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14, + 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21, + 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25, + 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31, + 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37, + 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26, + 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46, + 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62, + 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74, + 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86, + 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, + 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109, + 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116, + 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126, + 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131, + 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141, + 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148, + 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154, + 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, + 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, + 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172, + 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170, + 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26, + 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198, + 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178, + 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205, + 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210, + 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216, + 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9, + 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222, + 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225, + 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230, + 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234, + 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2, + 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246, + 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14, + 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14, + 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0, + 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0, + 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 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, 257, 26, 26, 26, 0, 265, 26, 26, 0, 0, 0, 0, - 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, - 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271, - 164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273, - 169, 169, 171, 26, 171, 171, 171, 171, 171, 171, 171, 171, 18, 18, 18, 18, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, - 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 280, - 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291, - 292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 168, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 280, 26, 290, 290, - 168, 168, 168, 295, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 296, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 297, - 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0, - 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0, - 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, - 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301, - 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, - 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26, - 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 306, 2, 2, 2, 2, 2, 2, 2, 307, 308, 309, 26, 26, 310, 2, - 311, 311, 311, 311, 311, 312, 0, 313, 314, 314, 314, 314, 314, 314, 314, 26, - 315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318, 53, 53, 53, 53, - 319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324, - 325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328, - 329, 329, 329, 329, 329, 329, 330, 26, 329, 331, 329, 332, 163, 163, 163, 163, - 333, 333, 333, 333, 333, 333, 333, 333, 334, 26, 26, 335, 336, 336, 337, 26, - 338, 338, 338, 26, 171, 171, 2, 2, 2, 2, 2, 339, 340, 341, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343, - 168, 168, 168, 168, 344, 26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26, + 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273, + 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172, + 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285, + 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291, + 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294, + 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0, + 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291, + 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, + 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299, + 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303, + 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305, + 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2, + 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314, + 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316, + 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322, + 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326, + 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26, + 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334, + 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2, + 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169, + 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352, + 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31, + 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0, + 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3, + 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296, + 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372, + 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382, + 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388, + 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394, + 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402, + 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405, + 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412, + 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413, + 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26, + 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308, + 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422, + 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26, + 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435, + 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438, + 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446, + 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26, + 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455, + 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464, + 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26, + 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26, + 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476, + 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480, + 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484, + 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488, + 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494, + 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498, + 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501, + 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509, + 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518, + 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524, + 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527, + 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529, + 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531, + 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536, + 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537, + 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543, + 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551, + 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553, + 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556, + 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178, + 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562, + 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574, + 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587, + 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26, + 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592, + 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592, + 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592, + 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597, + 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599, + 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, + 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601, + 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, + 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305, + 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603, + 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608, + 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612, + 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346, 26, 26, 26, 26, - 347, 26, 348, 349, 25, 25, 350, 351, 352, 25, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 353, 26, 354, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 355, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 356, 31, 31, 31, 31, 31, 31, 357, 26, 26, 26, 26, 31, 31, - 9, 9, 0, 313, 9, 358, 0, 0, 0, 0, 359, 0, 257, 280, 360, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 361, - 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290, - 290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257, 26, 367, - 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373, - 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378, - 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 280, - 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390, - 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26, - 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397, - 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402, - 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408, - 407, 408, 409, 407, 410, 407, 410, 411, 26, 26, 26, 26, 26, 26, 26, 26, - 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, - 412, 412, 412, 412, 412, 412, 413, 26, 412, 412, 414, 26, 412, 26, 26, 26, - 415, 2, 2, 2, 2, 2, 416, 307, 26, 26, 26, 26, 26, 26, 26, 26, - 417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424, - 425, 425, 425, 426, 427, 425, 26, 26, 26, 26, 26, 26, 428, 428, 429, 430, - 431, 431, 431, 432, 433, 433, 433, 434, 26, 26, 26, 26, 26, 26, 26, 26, - 435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436, - 439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447, - 448, 448, 448, 448, 26, 26, 26, 26, 449, 449, 449, 449, 450, 451, 450, 26, - 452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457, - 459, 459, 460, 461, 26, 462, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 463, 463, 463, 463, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, 26, 26, - 465, 465, 465, 465, 465, 465, 466, 26, 465, 465, 465, 465, 465, 465, 466, 467, - 468, 468, 468, 468, 468, 26, 468, 469, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50, - 470, 470, 470, 470, 470, 471, 472, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 473, 473, 473, 473, 473, 26, 474, 474, 474, 474, 474, 475, 26, 26, 476, 476, - 476, 477, 26, 26, 26, 26, 478, 478, 478, 479, 26, 26, 480, 480, 481, 26, - 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485, - 486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491, - 492, 492, 492, 492, 492, 492, 493, 492, 492, 26, 494, 494, 494, 494, 495, 26, - 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498, 26, - 499, 499, 500, 499, 499, 499, 499, 501, 26, 26, 26, 26, 26, 26, 26, 26, - 502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509, - 510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521, 26, - 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524, 26, 26, 26, - 525, 525, 525, 525, 525, 525, 525, 525, 525, 26, 525, 526, 26, 26, 26, 26, - 527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528, 26, 26, 26, 26, - 529, 529, 529, 529, 529, 529, 529, 529, 530, 26, 529, 531, 197, 532, 26, 26, - 533, 533, 533, 533, 533, 533, 533, 534, 533, 534, 26, 26, 26, 26, 26, 26, - 535, 535, 535, 536, 535, 537, 535, 535, 538, 26, 26, 26, 26, 26, 26, 26, - 539, 539, 539, 539, 539, 539, 539, 540, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543, - 544, 545, 546, 547, 547, 547, 548, 549, 544, 26, 547, 550, 26, 26, 26, 26, - 26, 26, 26, 26, 551, 552, 551, 551, 551, 551, 551, 552, 553, 26, 26, 26, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 26, 555, 555, 555, 555, 555, 555, - 555, 555, 555, 555, 556, 26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558, - 559, 560, 559, 559, 559, 559, 561, 559, 562, 26, 559, 559, 559, 563, 564, 564, - 564, 564, 565, 564, 564, 566, 567, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 568, 569, 570, 570, 570, 570, 568, 571, 570, 26, 570, 572, 573, 574, 575, 575, - 575, 576, 577, 578, 575, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 580, 580, 580, 581, - 26, 26, 26, 26, 26, 26, 582, 26, 108, 108, 108, 108, 108, 108, 583, 584, - 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, - 585, 585, 585, 586, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588, 26, - 585, 585, 585, 585, 585, 585, 585, 585, 589, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591, 26, - 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, - 592, 592, 592, 592, 592, 593, 592, 594, 26, 26, 26, 26, 26, 26, 26, 26, - 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, - 595, 595, 595, 595, 595, 595, 595, 595, 596, 26, 26, 26, 26, 26, 26, 26, - 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, - 304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601, - 601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605, 26, - 606, 606, 606, 606, 606, 606, 606, 606, 607, 26, 606, 608, 608, 606, 606, 609, - 606, 606, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 610, 610, 610, 610, 610, 610, 610, 610, - 610, 610, 610, 611, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612, - 612, 614, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 615, 26, 346, 26, - 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, - 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 26, - 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, - 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618, 26, 26, 26, 26, 26, - 616, 619, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 620, 621, - 622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 623, 26, 26, 26, 26, 26, 624, 26, 625, 26, 626, 626, - 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, - 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627, - 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630, - 628, 631, 628, 632, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 9, 9, 9, 9, 9, 633, 9, 9, 220, 26, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, - 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 634, 635, 0, 636, - 637, 638, 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, 0, 265, 26, 26, - 14, 14, 14, 14, 14, 14, 14, 14, 246, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 280, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 26, 0, 0, 0, 259, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, - 0, 0, 0, 254, 640, 641, 0, 642, 643, 0, 0, 0, 0, 0, 0, 0, - 268, 644, 254, 254, 0, 0, 0, 645, 646, 647, 648, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, - 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, - 649, 650, 26, 651, 652, 649, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 2, 2, 2, 347, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 653, 269, 269, 654, 655, 656, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 657, 657, 657, 657, 657, 658, 657, 659, 657, 660, 26, 26, 26, 26, 26, 26, - 26, 26, 661, 661, 661, 662, 26, 26, 663, 663, 663, 663, 663, 663, 663, 664, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 171, 665, 169, 171, - 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, - 666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668, 26, 26, 26, 26, 26, - 669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0, - 0, 0, 0, 0, 0, 0, 376, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 362, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26, - 672, 31, 31, 31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680, - 31, 681, 31, 682, 683, 681, 31, 682, 26, 26, 26, 26, 26, 26, 51, 26, - 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 280, 26, 0, 257, 362, 0, 362, 0, 362, 0, 0, 0, 275, 26, - 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 684, 0, 0, 0, - 685, 26, 0, 0, 0, 0, 0, 280, 0, 259, 313, 26, 275, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686, 0, 376, 0, 376, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 280, 259, 26, - 0, 280, 0, 0, 0, 0, 0, 0, 0, 26, 0, 313, 0, 0, 0, 0, - 0, 26, 0, 0, 0, 275, 313, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 0, 275, 376, 376, - 257, 26, 0, 0, 0, 376, 0, 265, 275, 26, 0, 313, 0, 26, 257, 26, - 0, 0, 359, 0, 0, 0, 0, 0, 0, 265, 26, 26, 26, 26, 0, 313, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 346, 26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687, 26, 26, 26, - 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 688, 26, 26, 26, 26, 26, 26, - 689, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618, + 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26, + 26, 26, 26, 26, 621, 26, 347, 26, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 26, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26, + 26, 26, 631, 26, 632, 26, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, + 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, + 633, 633, 633, 633, 633, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635, + 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9, + 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0, + 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0, + 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14, + 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649, + 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652, + 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656, + 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18, + 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669, + 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26, + 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 172, 677, 170, 172, 678, 678, 678, 678, 678, 678, 678, 678, + 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, + 679, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681, + 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276, + 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688, + 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694, + 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0, + 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26, + 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281, + 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0, + 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269, + 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0, + 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, + 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, + 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147, + 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, + 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, + 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, + 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0, + 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, + 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035, + 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250, + 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0, + 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299, + 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1093,1280, 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, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340, + 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177, + 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0, + 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165, + 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279, + 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, + 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5, + 1434,1438,1443, 0,1450, 0,1455,1461,1514, 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,1446,1458,1468,1476,1480,1486,1517, 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,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, + 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, + 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, + 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, + 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0, + 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648, + 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, + 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0, + 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, + 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0, + 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142, + 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, + 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, + 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210, + 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222, + 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243, + 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389, + 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284, + 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291, + 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260, + 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343, + 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, + 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698, + 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359, + 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274, + 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304, + 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707, + 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0, + 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743, + 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770, + 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0, + 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, + 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800, + 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24, + 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714, + 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750, + 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807, + 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825, + 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829, + 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515, + 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518, + 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830, + 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, + 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, + 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, + 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0, + 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0, + 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, + 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0, + 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, + 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, + 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0, + 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, + 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, + 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929, + 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, + 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, + 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, + 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, + 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, + 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, + 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, + 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, + 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, + 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, + 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, + 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, + 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, + 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, + 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, + 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, + 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, + 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, + 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, + 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, + 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, + 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, + 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, + 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, + 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, + 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, + 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, + 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, + 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, + 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, + 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0, + 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599, + 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, - 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, - 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, - 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, - 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, - 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, - 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, - 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, - 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, - 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, - 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, - 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, - 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, - 1280, 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, 949,1134,1010, - 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, - 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, - 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, - 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, - 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, - 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, - 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, - 1514, 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,1446,1458,1468,1476,1480,1486, - 1517, 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,1489,1503,1494,1500,1508, 0, - 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, - 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, - 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, - 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, - 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, - 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, - 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, - 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, - 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, - 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, - 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, - 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, - 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, - 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, - 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, - 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, - 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, - 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, - 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, - 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, - 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, - 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, - 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, - 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, - 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, - 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, - 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, - 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, - 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, - 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, - 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, - 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, - 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, - 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, - 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, - 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, - 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, - 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, - 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, - 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, - 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, - 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, - 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, - 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, - 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, - 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, - 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, - 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, - 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, - 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, - 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, - 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, - 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, - 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, - 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, - 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, - 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, - 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, - 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, - 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, - 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, - 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, - 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, - 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, - 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, - 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, - 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, - 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, - 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, - 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, - 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, - 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, - 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, - 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, - 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, - 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, - 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, - 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, - 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, - 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, - 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, - 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, - 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, - 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, - 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, - 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, - 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, - 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, - 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, - 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, - 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, - 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950, - 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959, - 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, - 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, - 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, - 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, - 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, - 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, - 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, - 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, - 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, - 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, - 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, - 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, - 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, - 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, - 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, - 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, - 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, - 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, - 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, - 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, - 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, - 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, - 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, - 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, - 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, - 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, - 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, - 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, - 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, - 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, - 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, - 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, - 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, - 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, + 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, + 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, + 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, + 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, + 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, + 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, + 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, + 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, + 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, + 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, + 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, + 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, + 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, + 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, + 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, + 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, + 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, + 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, + 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, + 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, + 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, + 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, + 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, + 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, + 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, + 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, + 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, + 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, + 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, + 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, + 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, + 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, + 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, + 817, 818, 819, 820, 821, 935, 0, 0, }; static const int16_t _hb_ucd_i16[196] = @@ -2792,12 +2822,12 @@ _hb_ucd_i16[196] = static inline uint_fast8_t _hb_ucd_gc (unsigned u) { - return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; } static inline uint_fast8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[8984+(((_hb_ucd_u8[7960+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0; + return u<125259u?_hb_ucd_u8[9184+(((_hb_ucd_u8[8128+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0; } static inline unsigned _hb_ucd_b4 (const uint8_t* a, unsigned i) @@ -2807,24 +2837,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i) static inline int_fast16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9728+(((_hb_ucd_u8[9608+(((_hb_ucd_b4(9480+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9932+(((_hb_ucd_u8[9812+(((_hb_ucd_b4(9684+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; } static inline uint_fast8_t _hb_ucd_sc (unsigned u) { - return u<918000u?_hb_ucd_u8[11234+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10514+(((_hb_ucd_u8[10064+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; + return u<918000u?_hb_ucd_u8[11454+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10718+(((_hb_ucd_u8[10268+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; } static inline uint_fast16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[17136+(((_hb_ucd_u8[16754+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; + return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17460+(((_hb_ucd_u8[17078+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; } #elif !defined(HB_NO_UCD_UNASSIGNED) static const uint8_t -_hb_ucd_u8[17564] = +_hb_ucd_u8[17868] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14, @@ -2832,7 +2862,7 @@ _hb_ucd_u8[17564] = 25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42, - 7, 7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 7, 7, 43, 7, 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, @@ -2854,12 +2884,12 @@ _hb_ucd_u8[17564] = 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 47, 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, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43, @@ -2878,35 +2908,36 @@ _hb_ucd_u8[17564] = 118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131, 132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146, 147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122, - 160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171, - 34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175, - 34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122, + 160,161,162,163,164,165,166,122,167,168,169,170,122,171,172,173, + 34, 34, 34, 34, 34, 34, 34,174,175, 34,176,122,122,122,122,122, + 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,177, + 34, 34, 34, 34, 34, 34, 34, 34,178,122,122,122,122,122,122,122, 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, - 122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122, - 34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186, - 34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189, - 34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122, - 122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195, - 69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209, - 69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122, - 213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216, - 34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122, - 224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232, - 233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34, - 240, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,241, 34, 34, - 34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122, - 34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122, - 34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122, - 245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122, - 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248, - 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249, + 122,122,122,122,122,122,122,122, 34, 34, 34, 34,179,122,122,122, + 34, 34, 34, 34,180,181,182,183,122,122,122,122,184,185,186,187, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,188, + 34, 34, 34, 34, 34, 34, 34, 34, 34,189,190,122,122,122,122,122, + 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,191, + 34, 34,192, 34, 34,193,122,122,122,122,122,122,122,122,122,122, + 122,122,122,122,122,122,122,122,194,195,122,122,122,122,122,122, + 122,122,122,122,122,122,122,122,122,122,122,122,122,122,196,197, + 69,198,199,200,201,202,203,122,204,205,206,207,208,209,210,211, + 69, 69, 69, 69,212,213,122,122,122,122,122,122,122,122,214,122, + 215,216,217,122,122,218,122,122,122,219,122,122,122,122,122,220, + 34,221,222,122,122,122,122,122,223,224,225,122,226,227,122,122, + 228,229,230,231,232,122, 69,233, 69, 69, 69, 69, 69,234,235,236, + 237,238, 69, 69,239,240, 69,241,122,122,122,122,122,122,122,122, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,242, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34, + 244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34, + 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122, + 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122, + 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122, + 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, @@ -2969,7 +3000,7 @@ _hb_ucd_u8[17564] = 44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91, 70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87, 86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61, - 62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36, + 62, 94, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77, 44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36, 57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36, @@ -2979,7 +3010,7 @@ _hb_ucd_u8[17564] = 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36, 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44, - 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36, + 36, 36, 61, 81, 43, 43, 43, 80, 7, 7, 7, 7, 7, 44, 36, 36, 77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67, 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, @@ -3146,18 +3177,19 @@ _hb_ucd_u8[17564] = 44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44, 16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44, - 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44, - 180, 27, 30, 2, 2, 44, 44, 44, 36, 43, 43, 2, 2, 44, 44, 44, - 36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44, - 27, 27, 27, 7, 7, 7, 7, 7, 71, 70, 71, 44, 44, 44, 44, 57, - 86, 87, 43, 85, 87, 60,185, 2, 2, 80, 44, 44, 44, 44, 79, 44, - 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43, - 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 94, 98, 44, 44, 44, 44, - 36, 70, 2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85, - 98, 36, 63, 2, 59, 43, 60, 87, 7, 7, 7, 7, 7, 63, 63, 2, - 179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44, - 36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43, 2, 2, 2, 80, + 36, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 43, + 27, 27, 27, 95, 44, 44, 44, 44,180, 27, 30, 2, 2, 44, 44, 44, + 36, 43, 43, 2, 2, 44, 44, 44, 36, 36,183, 27, 27, 27, 44, 44, + 87, 98, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, + 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7, + 71, 70, 71, 44, 44, 44, 44, 57, 86, 87, 43, 85, 87, 60,185, 2, + 2, 80, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 70, 43, 43, 87, 43, 43, 43, 80, 7, 7, 7, 7, 7, + 2, 2, 94, 98, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44, + 36, 94, 86, 43, 43, 43, 43, 85, 98, 36, 63, 2, 59, 43, 60, 87, + 7, 7, 7, 7, 7, 63, 63, 2,179, 27, 27, 27, 27, 27, 27, 27, + 27, 27,100, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 86, 87, + 43, 86, 85, 43, 2, 2, 2, 71, 70, 44, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70, 86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62, @@ -3179,17 +3211,20 @@ _hb_ucd_u8[17564] = 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60, 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2, - 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87, - 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36, - 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43, - 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36, - 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44, - 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90, - 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44, + 2, 64, 44, 44, 44, 44, 44, 44, 2, 2, 2, 2, 2, 44, 44, 44, + 43, 43, 43, 80, 43, 43, 43, 87, 63, 2, 2, 44, 44, 44, 44, 44, + 2, 36, 36, 36, 36, 36, 36, 36, 44, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 89, 43, 43, 43, 85, 43, 87, 80, 44, 44, 44, 44, + 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57, + 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36, + 36, 36, 36, 36, 36, 86, 86, 90, 43, 89, 87, 87, 61, 44, 44, 44, + 36, 70, 85,107, 64, 44, 44, 44, 43, 94, 36, 36, 36, 36, 36, 36, + 36, 36, 86, 43, 43, 80, 44, 86, 85, 60, 2, 2, 2, 2, 2, 2, 27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181, 2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44, - 65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44, + 65, 65, 65, 65, 65, 65, 65, 65, 71, 36, 36, 70, 43, 43, 43, 43, + 43, 43, 43, 44, 44, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44, 7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44, @@ -3197,7 +3232,8 @@ _hb_ucd_u8[17564] = 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44, 86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81, - 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, + 36, 61, 44, 44, 44, 44, 44, 44, 44, 61, 44, 44, 44, 44, 44, 44, + 36, 61, 62, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44, 67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86, @@ -3222,10 +3258,12 @@ _hb_ucd_u8[17564] = 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67, 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43, 16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110, - 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43, - 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44, - 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80, - 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 96, + 44, 44,150, 16, 16,110, 44, 44, 43, 43, 43, 80, 43, 43, 43, 43, + 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44, + 40, 40, 40, 40, 40, 40, 40, 44, 44, 44, 44, 44, 44, 44, 44, 57, + 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77, + 36, 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 43, 43, + 7, 7, 7, 7, 7, 44, 44, 96, 36, 36, 36, 36, 36, 83, 43, 43, 36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27, 16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27, 188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163, @@ -3238,206 +3276,210 @@ _hb_ucd_u8[17564] = 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67, - 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44, + 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67, + 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, + 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44, - 65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44, - 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21, - 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, - 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, - 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, - 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, - 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, - 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11, - 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12, - 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26, - 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, - 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6, - 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26, - 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15, - 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21, - 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24, - 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28, - 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, - 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5, - 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, - 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, - 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, - 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, - 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15, - 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1, - 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, - 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0, + 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, + 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, + 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, + 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, + 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5, + 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2, + 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26, + 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21, + 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, + 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1, + 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12, + 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7, + 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22, + 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6, + 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1, + 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, + 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2, + 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, + 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, + 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6, + 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, + 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, + 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, + 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, + 15, 0, 16, 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, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 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, 20, - 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 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, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 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, 35, + 0, 36, 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, - 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, - 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, - 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18, - 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, - 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, - 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, - 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, - 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, - 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, - 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, - 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 75, 0, 0, 76, 77, 0, - 0, 78, 79, 0, 80, 62, 0, 81, 82, 0, 0, 83, 84, 85, 0, 0, - 0, 86, 0, 87, 0, 0, 51, 88, 51, 0, 89, 0, 90, 0, 0, 0, - 79, 0, 0, 0, 91, 92, 0, 93, 94, 95, 96, 0, 0, 0, 0, 0, - 51, 0, 0, 0, 0, 97, 98, 0, 0, 0, 0, 99,100, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,101, 0, 0,102, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,103,104, 0, 0,105, 0, 0, 0, 0, 0, 0, - 106, 0, 0, 0,100, 0, 0, 0, 0, 0,107,108, 0, 0, 0, 0, - 0, 0, 0,109, 0,110, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, - 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, - 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, - 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, - 0, 27, 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, - 33, 0, 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, - 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, - 42, 0, 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, - 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, - 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, - 0, 56, 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, - 0, 0, 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, - 0, 0, 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, - 0, 0, 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, - 0, 81, 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, - 84, 0, 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, - 0, 0, 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, - 0, 0, 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, - 0, 0, 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, - 0, 0, 98, 0, 0, 0, 99, 0,100, 93, 0, 0,101, 0, 0, 0, - 84, 0, 0,102, 0, 0, 0,103,104, 0, 0,105,106, 0, 0, 0, - 0, 0, 0,107, 0, 0,108, 0, 0, 0, 0,109, 33, 0,110,111, - 112, 35, 0, 0,113, 0, 0, 0,114, 0, 0, 0, 0, 0, 0,115, - 0, 0,116, 0, 0, 0, 0,117, 88, 0, 0, 0, 0, 0, 57, 0, - 0, 0, 0, 52,118, 0, 0, 0, 0,119, 0, 0,120, 0, 0, 0, - 0,118, 0, 0, 0, 0, 0,121, 0, 0, 0,122, 0, 0, 0,123, - 0,124, 0, 0, 0, 0,125,126,127, 0,128, 0,129, 0, 0, 0, - 130,131,132, 0, 0, 0, 35, 0, 0, 0,133, 0, 0,134, 0, 0, - 135, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, - 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, - 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, - 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, - 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, - 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, - 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, - 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, - 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, - 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, - 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, - 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, - 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, - 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, - 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, - 1, 52, 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, - 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, - 0, 78, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, - 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, - 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, - 0, 0, 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50, - 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68, - 61, 0, 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, - 0, 0, 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, - 0, 0, 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0, - 0, 0, 19, 58, 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, - 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, - 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, - 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, - 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, - 0, 0, 56, 0, 89, 80, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, + 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, + 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, + 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, + 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, + 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, + 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, + 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, + 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, + 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82, + 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89, + 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94, + 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0, + 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0, + 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0, + 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0, + 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16, + 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23, + 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31, + 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0, + 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, + 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44, + 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0, + 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58, + 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63, + 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70, + 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79, + 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82, + 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78, + 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0, + 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0, + 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94, + 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0, + 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103, + 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108, + 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0, + 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0, + 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52, + 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0, + 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125, + 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0, + 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0, + 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, + 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0, + 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, + 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0, + 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45, + 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1, + 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14, + 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55, + 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0, + 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0, + 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0, + 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0, + 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0, + 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, + 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87, + 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, + 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4, + 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, + 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0, + 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102, + 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, + 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0, + 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, + 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61, + 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51, + 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0, + 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0, + 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0, + 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0, + 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, + 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0, 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4, 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1, - 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 4,122, 0, 0, - 0, 1,123, 0, 0, 0, 0, 0,230,230,230,230,230,232,220,220, - 220,220,232,216,220,220,220,220,220,202,202,220,220,220,220,202, - 202,220,220,220, 1, 1, 1, 1, 1,220,220,220,220,230,230,230, - 230,240,230,220,220,220,230,230,230,220,220, 0,230,230,230,220, - 220,220,220,230,232,220,220,230,233,234,234,233,234,234,233,230, - 0, 0, 0,230, 0,220,230,230,230,230,220,230,230,230,222,220, - 230,230,220,220,230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, - 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, - 230,220,220,230,220,230,230,220, 35, 0, 0, 0, 0, 0,230,230, - 230, 0, 0,230,230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0, - 230,220,230,230,220,220,230,220,220,230,220,230,220,230,230, 0, - 0,220, 0, 0,230,230, 0,230, 0,230,230,230,230,230, 0, 0, - 0,220,220,220,230,220,220,220,230,230, 0,220, 27, 28, 29,230, - 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, - 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, - 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0, - 122,122,122,122,220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, - 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0, - 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, - 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, - 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,230,220, 0,220, - 230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1, - 1, 0, 0, 0,230,234,214,220,202,230,230,230,230,230,232,228, - 228,220,218,230,233,220,230,220,230,230, 1, 1, 1, 1, 1,230, - 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,232,222,224,224, - 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, - 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, - 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, - 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, - 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,220,220,220, 0, - 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19, - 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123, + 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230, + 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220, + 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220, + 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0, + 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233, + 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230, + 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0, + 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, + 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0, + 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0, + 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230, + 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230, + 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220, + 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230, + 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107, + 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220, + 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130, + 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, + 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, + 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220, + 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0, + 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230, + 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1, + 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228, + 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230, + 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, + 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, + 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, + 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0, + 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 17, + 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113, + 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, - 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28, - 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0, - 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, - 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, - 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, - 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, - 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12, - 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19, - 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8, - 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27, - 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0, - 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20, - 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20, - 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20, - 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0, - 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0, - 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45, - 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1, - 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, - 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13, - 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 13, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, + 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, + 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, + 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, + 0, 0, 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, + 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, + 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, + 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, + 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, + 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, + 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, + 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, + 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, + 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, + 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, + 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, + 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13, + 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13, + 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32, + 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, + 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, @@ -3459,130 +3501,131 @@ _hb_ucd_u8[17564] = 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 44, 0, 0, 1, - 2, 2, 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, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56, - 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61, - 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 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, 32, 33, 34, 35, 36, 37, 37, + 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, + 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, + 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101, + 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116, + 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131, + 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145, + 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158, + 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164, + 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171, + 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96, + 96, 96,178,179,180,181,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,183,182,182,182,182,182,182,184,184,184,185, + 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109, - 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123, - 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138, - 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151, - 152,153,154,155, 96, 96,156,157,158,159, 96,160, 96,161,162,162, - 162,162,162,162,162,163,164,162,165, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,166,167,167, - 167,167,167,167,167,167,168, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96, 96, 96,171,171, - 171,171,172,173,174,175, 96, 96, 96, 96,176,177,178,179,180,180, - 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, - 180,180,180,180,180,180,180,180,180,180,180,180,180,181,180,180, - 180,180,180,180,182,182,182,183,184, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,185,186,187, - 188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194, 59,195, - 196,197,198,199,200, 96,201,202,203, 59, 59,204, 59,205,206,206, - 206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96,208, 96,209, 96, - 210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96, 96,212,213,214, - 215, 96, 96, 96, 96, 96,216,217,218, 96,219,220, 96, 96,221,222, - 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225,226,227,228,229, - 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,234, 70,235, 70, + 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204, + 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96, + 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215, + 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221, + 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59, + 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96, + 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236, 70, 70, 70, 70, - 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, - 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, - 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96, 96, 96,240, 96, - 241,242, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, - 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0, - 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, - 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, - 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, - 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, - 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, - 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, - 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, - 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, - 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, - 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, - 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5, - 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, - 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, - 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, - 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2, - 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5, - 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11, - 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, - 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, - 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, - 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11, - 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2, - 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10, - 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, - 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, - 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, - 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2, - 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, - 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21, - 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, - 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, - 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, - 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, - 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, - 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, - 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, - 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, - 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, - 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, - 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, - 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23, - 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, - 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, - 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16, - 16, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2, - 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36, - 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, - 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, - 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, - 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18, - 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, - 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, + 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 96, 96, + 96, 96, 96, 96, 96, 96, 70, 70, 70, 70,242, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,243, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,244, 96, 96, + 96, 96, 96, 96, 96, 96,245, 96,246,247, 0, 1, 2, 2, 0, 1, + 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, + 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, + 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, + 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, + 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3, + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, + 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, + 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, + 2, 2, 2, 2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, + 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, + 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, + 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2, + 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, + 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, + 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, + 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2, + 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, + 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, + 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, + 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10, + 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, + 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, + 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, + 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, + 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, + 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, + 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, + 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, + 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, + 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, + 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2, + 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, + 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2, + 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2, + 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16, + 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, + 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, + 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, + 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2, + 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, + 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, + 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, + 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, @@ -3741,49 +3784,50 @@ _hb_ucd_u8[17564] = 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144, 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,156,156, 156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156, - 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,148,148, - 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158, - 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153, - 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149, - 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, - 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2, - 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111, 2,100,100, - 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108, - 2,108,108,108,108,108,108,108,108,108,108,108,108, 2,129,129, - 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129, - 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129, - 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, - 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107, - 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2, - 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2, - 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107, - 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2, - 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107, - 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137, - 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137, - 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, - 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123, - 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114, - 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32, - 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, - 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126, - 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126,126, - 126,126,126,126,126, 2,142,142,142,142,142,142,142,142,142,142, - 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125, - 125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,154,154, - 154,154,154,154,154, 2, 2,154, 2, 2,154,154,154,154,154,154, - 154,154, 2,154,154, 2,154,154,154,154,154,154,154,154,154,154, - 154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154,154, - 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2, - 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141, - 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140, - 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,147,147, + 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148, + 2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158, + 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153, + 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, + 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101, + 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, + 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108, + 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108, + 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, 2, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109, + 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109, + 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107, + 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107, + 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2, + 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2, + 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, + 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107, + 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137, + 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124, + 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123, + 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114, + 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102, + 102,102,102,102,102,102,102,102, 2, 2, 2, 2, 2, 2,126,126, + 126,126,126,126,126,126,126,126,126, 2, 2,126,126,126,126,126, + 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2,142,142, + 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125, + 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, + 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2, + 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150, + 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150, + 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140, + 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121, + 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2, 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133, 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134, @@ -3795,29 +3839,31 @@ _hb_ucd_u8[17564] = 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145, - 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2, 86, 2, + 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163, + 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163, + 163, 2, 2, 2,163,163,163,163, 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157, 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 80, 2, - 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127, - 127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115, - 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115, - 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159, - 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103, - 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119, - 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119, - 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146, - 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, - 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136, - 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155, - 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 17, - 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15, - 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 15, 15, - 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2,127,127, + 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 79, 2, + 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115, + 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159, + 159,159,159,159,159,159,159,159,159,159,159,159,159, 2,159,159, + 2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103, + 103,103,103,103, 2, 2,119,119,119,119,119,119,119,119,119,119, + 119,119,119,119, 2, 2,119,119, 2,119,119,119,119,119, 2, 2, + 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146, + 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139, + 13, 13,155, 2, 2, 2,136,136,136,136,136,136,136,136,155,155, + 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2,136, 2, + 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17, + 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 17, 17, + 17, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 15, 15, + 15, 2, 2, 17, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139, 139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105, 105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105, 105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105, @@ -3831,24 +3877,27 @@ _hb_ucd_u8[17564] = 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131, 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131, - 131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2, - 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56, - 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151, - 151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151, - 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160, - 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152, - 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 2, 30, 30, 2,113,113, - 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, - 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132, - 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3, - 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, - 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, - 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, - 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, - 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13, + 131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, 56, + 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, + 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, 6, + 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151,151, + 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151, + 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,160,160, + 160,160,160,160,160,160,160,160,160,160,160,160,160, 2,152,152, + 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164, + 164,164,164,164,164,164,164,164, 2, 2, 2, 2, 2, 2, 30, 30, + 30, 30, 2, 30, 30, 2,113,113,113,113,113,113,113,113,113,113, + 113,113,113, 2, 2,113,113,113,113,113,113,113,113, 2,132,132, + 132,132,132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132, + 2, 2, 2, 2,132,132, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, + 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, + 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, + 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -3926,7 +3975,7 @@ _hb_ucd_u8[17564] = 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, }; static const uint16_t -_hb_ucd_u16[9200] = +_hb_ucd_u16[9320] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -4000,509 +4049,517 @@ _hb_ucd_u16[9200] = 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140, 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474, 48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476, - 48, 48, 477, 478, 140, 140, 140, 140, 48, 464, 479, 48, 62, 480, 140, 48, - 481, 140, 140, 48, 482, 140, 48, 314, 483, 48, 48, 484, 485, 457, 486, 487, - 222, 48, 48, 488, 489, 48, 196, 192, 490, 48, 491, 492, 493, 48, 48, 494, - 222, 48, 48, 495, 496, 497, 498, 499, 48, 97, 500, 501, 140, 140, 140, 140, - 502, 503, 504, 48, 48, 505, 506, 192, 507, 83, 84, 508, 509, 510, 511, 512, - 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140, - 48, 48, 518, 519, 520, 521, 140, 140, 48, 48, 48, 522, 523, 192, 524, 140, - 48, 48, 525, 526, 192, 140, 140, 140, 48, 173, 527, 528, 314, 140, 140, 140, - 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530, - 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140, - 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196, - 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140, - 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 48, 557, 140, 140, 140, 100, 271, 558, 559, 560, - 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562, - 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563, - 48, 48, 200, 564, 140, 140, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140, - 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565, - 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578, + 48, 48, 477, 478, 140, 140, 140, 479, 48, 464, 480, 48, 62, 481, 140, 48, + 482, 140, 140, 48, 483, 140, 48, 314, 484, 48, 48, 485, 486, 457, 487, 488, + 222, 48, 48, 489, 490, 48, 196, 192, 491, 48, 492, 493, 494, 48, 48, 495, + 222, 48, 48, 496, 497, 498, 499, 500, 48, 97, 501, 502, 503, 140, 140, 140, + 504, 505, 506, 48, 48, 507, 508, 192, 509, 83, 84, 510, 511, 512, 513, 514, + 48, 48, 48, 515, 516, 517, 478, 140, 48, 48, 48, 518, 519, 192, 140, 140, + 48, 48, 520, 521, 522, 523, 140, 140, 48, 48, 48, 524, 525, 192, 526, 140, + 48, 48, 527, 528, 192, 140, 140, 140, 48, 173, 529, 530, 314, 140, 140, 140, + 48, 48, 501, 531, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 532, + 533, 534, 48, 535, 536, 192, 140, 140, 140, 140, 537, 48, 48, 538, 539, 140, + 540, 48, 48, 541, 542, 543, 48, 48, 544, 545, 546, 48, 48, 48, 48, 196, + 547, 140, 140, 140, 140, 140, 140, 140, 84, 48, 520, 548, 549, 148, 175, 550, + 48, 551, 552, 553, 140, 140, 140, 140, 554, 48, 48, 555, 556, 192, 557, 48, + 558, 559, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 560, + 561, 115, 48, 562, 563, 192, 140, 140, 140, 140, 140, 100, 271, 564, 565, 566, + 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 567, 568, + 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 569, + 48, 48, 48, 570, 571, 572, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140, + 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 573, + 48, 48, 48, 574, 575, 576, 577, 578, 48, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 9, 9, 11, 11, 271, 579, 140, 140, 140, 140, 140, 140, + 48, 48, 48, 48, 580, 581, 582, 582, 583, 584, 140, 140, 140, 140, 585, 586, 48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140, - 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579, - 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 206, - 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140, - 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588, - 589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461, - 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11, - 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11, - 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613, - 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622, - 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140, - 628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140, - 48, 48, 151, 633, 634, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637, - 140, 140, 140, 140, 140, 140, 638, 200, 48, 48, 48, 48, 639, 585, 140, 140, - 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498, - 271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140, - 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654, - 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324, - 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209, - 659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662, - 209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323, - 209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209, - 664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665, - 287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192, - 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 196, 48, 48, 48, 48, + 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 587, + 48, 48, 588, 589, 140, 590, 591, 48, 48, 48, 48, 48, 48, 48, 48, 206, + 48, 48, 48, 48, 48, 48, 71, 151, 196, 592, 593, 140, 140, 140, 140, 140, + 32, 32, 594, 32, 595, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140, + 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 596, 209, 209, 209, 597, 598, + 599, 209, 600, 209, 209, 209, 288, 140, 209, 209, 209, 209, 601, 140, 140, 140, + 140, 140, 140, 140, 271, 602, 271, 602, 209, 209, 209, 209, 209, 287, 271, 461, + 9, 603, 11, 604, 605, 606, 241, 9, 607, 608, 609, 610, 611, 9, 603, 11, + 612, 613, 11, 614, 615, 616, 617, 9, 618, 11, 9, 603, 11, 604, 605, 11, + 241, 9, 607, 617, 9, 618, 11, 9, 603, 11, 619, 9, 620, 621, 622, 623, + 11, 624, 9, 625, 626, 627, 628, 11, 629, 9, 630, 11, 631, 632, 632, 632, + 32, 32, 32, 633, 32, 32, 634, 635, 636, 637, 45, 140, 140, 140, 140, 140, + 638, 639, 640, 140, 140, 140, 140, 140, 641, 642, 643, 27, 27, 27, 644, 140, + 645, 140, 140, 140, 140, 140, 140, 140, 48, 48, 151, 646, 647, 140, 140, 140, + 140, 48, 648, 140, 48, 48, 649, 650, 140, 140, 140, 140, 140, 48, 651, 192, + 140, 140, 140, 140, 140, 140, 652, 200, 48, 48, 48, 48, 653, 595, 140, 140, + 9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499, + 271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140, + 659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668, + 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324, + 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209, + 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676, + 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678, + 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209, + 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426, + 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192, + 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, - 391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, - 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11, - 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21, - 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26, - 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31, - 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31, - 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43, - 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31, - 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53, - 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67, - 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26, - 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91, - 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26, - 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112, - 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113, - 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26, - 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131, - 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26, - 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26, - 150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156, 26, 26, 26, 26, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157, - 157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162, 26, 26, 26, 26, - 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, - 163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167, - 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169, - 169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169, - 169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173, - 169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176, - 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, - 178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182, - 183, 183, 184, 185, 186, 186, 187, 26, 188, 188, 189, 26, 190, 191, 192, 26, - 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195, - 196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199, - 197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201, 26, - 202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208, 26, - 209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193, - 213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217, - 215, 218, 215, 218, 215, 219, 9, 9, 9, 220, 26, 26, 26, 26, 26, 26, - 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223, - 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227, - 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231, - 18, 232, 164, 164, 164, 164, 164, 233, 224, 26, 234, 9, 235, 236, 237, 238, - 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244, - 2, 2, 2, 2, 2, 2, 2, 245, 9, 9, 9, 9, 9, 9, 9, 9, - 14, 14, 246, 246, 14, 14, 14, 14, 246, 246, 14, 247, 14, 14, 14, 246, - 14, 14, 14, 14, 14, 14, 248, 14, 248, 14, 249, 250, 14, 14, 251, 252, - 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 255, 256, - 0, 257, 2, 258, 0, 0, 0, 0, 259, 26, 9, 9, 9, 9, 260, 26, - 0, 0, 0, 0, 261, 262, 4, 0, 0, 263, 0, 0, 2, 2, 2, 2, - 2, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140, + 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684, + 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4, + 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, + 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14, + 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21, + 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25, + 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31, + 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37, + 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26, + 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46, + 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62, + 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74, + 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86, + 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, + 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109, + 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116, + 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126, + 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131, + 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141, + 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148, + 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154, + 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, + 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, + 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172, + 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170, + 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26, + 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198, + 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178, + 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205, + 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210, + 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216, + 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9, + 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222, + 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225, + 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230, + 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234, + 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2, + 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246, + 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14, + 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14, + 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0, + 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0, + 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 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, 257, 26, 26, 26, 0, 265, 26, 26, 0, 0, 0, 0, - 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, - 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271, - 164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273, - 169, 169, 171, 26, 171, 171, 171, 171, 171, 171, 171, 171, 18, 18, 18, 18, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, - 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 280, - 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291, - 292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168, - 168, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 280, 26, 290, 290, - 168, 168, 168, 295, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 296, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 297, - 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0, - 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0, - 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, - 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301, - 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, - 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26, - 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 306, 2, 2, 2, 2, 2, 2, 2, 307, 308, 309, 26, 26, 310, 2, - 311, 311, 311, 311, 311, 312, 0, 313, 314, 314, 314, 314, 314, 314, 314, 26, - 315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318, 53, 53, 53, 53, - 319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324, - 325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328, - 329, 329, 329, 329, 329, 329, 330, 26, 329, 331, 329, 332, 163, 163, 163, 163, - 333, 333, 333, 333, 333, 333, 333, 333, 334, 26, 26, 335, 336, 336, 337, 26, - 338, 338, 338, 26, 171, 171, 2, 2, 2, 2, 2, 339, 340, 341, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343, - 168, 168, 168, 168, 344, 26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26, + 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273, + 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172, + 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285, + 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291, + 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294, + 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0, + 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291, + 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, + 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299, + 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303, + 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305, + 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2, + 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314, + 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316, + 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322, + 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326, + 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26, + 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334, + 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2, + 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169, + 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352, + 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31, + 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0, + 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3, + 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296, + 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372, + 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382, + 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388, + 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394, + 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397, + 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402, + 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405, + 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412, + 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413, + 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26, + 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308, + 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422, + 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26, + 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435, + 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438, + 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446, + 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26, + 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455, + 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464, + 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26, + 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26, + 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476, + 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480, + 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484, + 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488, + 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494, + 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498, + 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501, + 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509, + 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518, + 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524, + 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527, + 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529, + 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531, + 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536, + 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537, + 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543, + 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551, + 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553, + 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556, + 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178, + 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562, + 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574, + 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587, + 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26, + 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592, + 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592, + 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592, + 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597, + 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599, + 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, + 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601, + 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, + 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305, + 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603, + 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608, + 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612, + 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618, + 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26, + 26, 26, 26, 26, 621, 26, 347, 26, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 26, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346, 26, 26, 26, 26, - 347, 26, 348, 349, 25, 25, 350, 351, 352, 25, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 353, 26, 354, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 355, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 356, 31, 31, 31, 31, 31, 31, 357, 26, 26, 26, 26, 31, 31, - 9, 9, 0, 313, 9, 358, 0, 0, 0, 0, 359, 0, 257, 280, 360, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 361, - 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290, - 290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257, 26, 367, - 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373, - 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378, - 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 280, - 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390, - 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26, - 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397, - 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402, - 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408, - 407, 408, 409, 407, 410, 407, 410, 411, 26, 26, 26, 26, 26, 26, 26, 26, - 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, - 412, 412, 412, 412, 412, 412, 413, 26, 412, 412, 414, 26, 412, 26, 26, 26, - 415, 2, 2, 2, 2, 2, 416, 307, 26, 26, 26, 26, 26, 26, 26, 26, - 417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424, - 425, 425, 425, 426, 427, 425, 26, 26, 26, 26, 26, 26, 428, 428, 429, 430, - 431, 431, 431, 432, 433, 433, 433, 434, 26, 26, 26, 26, 26, 26, 26, 26, - 435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436, - 439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447, - 448, 448, 448, 448, 26, 26, 26, 26, 449, 449, 449, 449, 450, 451, 450, 26, - 452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457, - 459, 459, 460, 461, 26, 462, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 463, 463, 463, 463, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, 26, 26, - 465, 465, 465, 465, 465, 465, 466, 26, 465, 465, 465, 465, 465, 465, 466, 467, - 468, 468, 468, 468, 468, 26, 468, 469, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50, - 470, 470, 470, 470, 470, 471, 472, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 473, 473, 473, 473, 473, 26, 474, 474, 474, 474, 474, 475, 26, 26, 476, 476, - 476, 477, 26, 26, 26, 26, 478, 478, 478, 479, 26, 26, 480, 480, 481, 26, - 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485, - 486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491, - 492, 492, 492, 492, 492, 492, 493, 492, 492, 26, 494, 494, 494, 494, 495, 26, - 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498, 26, - 499, 499, 500, 499, 499, 499, 499, 501, 26, 26, 26, 26, 26, 26, 26, 26, - 502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509, - 510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521, 26, - 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524, 26, 26, 26, - 525, 525, 525, 525, 525, 525, 525, 525, 525, 26, 525, 526, 26, 26, 26, 26, - 527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528, 26, 26, 26, 26, - 529, 529, 529, 529, 529, 529, 529, 529, 530, 26, 529, 531, 197, 532, 26, 26, - 533, 533, 533, 533, 533, 533, 533, 534, 533, 534, 26, 26, 26, 26, 26, 26, - 535, 535, 535, 536, 535, 537, 535, 535, 538, 26, 26, 26, 26, 26, 26, 26, - 539, 539, 539, 539, 539, 539, 539, 540, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543, - 544, 545, 546, 547, 547, 547, 548, 549, 544, 26, 547, 550, 26, 26, 26, 26, - 26, 26, 26, 26, 551, 552, 551, 551, 551, 551, 551, 552, 553, 26, 26, 26, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 26, 555, 555, 555, 555, 555, 555, - 555, 555, 555, 555, 556, 26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558, - 559, 560, 559, 559, 559, 559, 561, 559, 562, 26, 559, 559, 559, 563, 564, 564, - 564, 564, 565, 564, 564, 566, 567, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 568, 569, 570, 570, 570, 570, 568, 571, 570, 26, 570, 572, 573, 574, 575, 575, - 575, 576, 577, 578, 575, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 580, 580, 580, 581, - 26, 26, 26, 26, 26, 26, 582, 26, 108, 108, 108, 108, 108, 108, 583, 584, - 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, - 585, 585, 585, 586, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588, 26, - 585, 585, 585, 585, 585, 585, 585, 585, 589, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591, 26, - 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, - 592, 592, 592, 592, 592, 593, 592, 594, 26, 26, 26, 26, 26, 26, 26, 26, - 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, - 595, 595, 595, 595, 595, 595, 595, 595, 596, 26, 26, 26, 26, 26, 26, 26, - 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, - 304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601, - 601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605, 26, - 606, 606, 606, 606, 606, 606, 606, 606, 607, 26, 606, 608, 608, 606, 606, 609, - 606, 606, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 610, 610, 610, 610, 610, 610, 610, 610, - 610, 610, 610, 611, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612, - 612, 614, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 615, 26, 346, 26, - 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, - 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 26, - 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, - 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618, 26, 26, 26, 26, 26, - 616, 619, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 620, 621, - 622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 623, 26, 26, 26, 26, 26, 624, 26, 625, 26, 626, 626, - 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, - 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627, - 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630, - 628, 631, 628, 632, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 9, 9, 9, 9, 9, 633, 9, 9, 220, 26, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, - 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 634, 635, 0, 636, - 637, 638, 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, 0, 265, 26, 26, - 14, 14, 14, 14, 14, 14, 14, 14, 246, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 280, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 26, 0, 0, 0, 259, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, - 0, 0, 0, 254, 640, 641, 0, 642, 643, 0, 0, 0, 0, 0, 0, 0, - 268, 644, 254, 254, 0, 0, 0, 645, 646, 647, 648, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, - 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, - 649, 650, 26, 651, 652, 649, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 2, 2, 2, 347, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 653, 269, 269, 654, 655, 656, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 657, 657, 657, 657, 657, 658, 657, 659, 657, 660, 26, 26, 26, 26, 26, 26, - 26, 26, 661, 661, 661, 662, 26, 26, 663, 663, 663, 663, 663, 663, 663, 664, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 171, 665, 169, 171, - 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, - 666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668, 26, 26, 26, 26, 26, - 669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0, - 0, 0, 0, 0, 0, 0, 376, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 362, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26, - 672, 31, 31, 31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680, - 31, 681, 31, 682, 683, 681, 31, 682, 26, 26, 26, 26, 26, 26, 51, 26, - 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 280, 26, 0, 257, 362, 0, 362, 0, 362, 0, 0, 0, 275, 26, - 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 684, 0, 0, 0, - 685, 26, 0, 0, 0, 0, 0, 280, 0, 259, 313, 26, 275, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686, 0, 376, 0, 376, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 280, 259, 26, - 0, 280, 0, 0, 0, 0, 0, 0, 0, 26, 0, 313, 0, 0, 0, 0, - 0, 26, 0, 0, 0, 275, 313, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 0, 275, 376, 376, - 257, 26, 0, 0, 0, 376, 0, 265, 275, 26, 0, 313, 0, 26, 257, 26, - 0, 0, 359, 0, 0, 0, 0, 0, 0, 265, 26, 26, 26, 26, 0, 313, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 346, 26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687, 26, 26, 26, - 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 688, 26, 26, 26, 26, 26, 26, - 689, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26, + 26, 26, 631, 26, 632, 26, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, + 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, + 633, 633, 633, 633, 633, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635, + 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9, + 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0, + 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0, + 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14, + 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649, + 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652, + 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656, + 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18, + 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669, + 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26, + 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 172, 677, 170, 172, 678, 678, 678, 678, 678, 678, 678, 678, + 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, 678, + 679, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681, + 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276, + 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688, + 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694, + 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0, + 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26, + 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281, + 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0, + 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269, + 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0, + 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, + 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, + 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147, + 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, + 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, + 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, + 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0, + 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, + 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035, + 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250, + 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0, + 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299, + 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1093,1280, 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, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340, + 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177, + 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0, + 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165, + 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279, + 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, + 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5, + 1434,1438,1443, 0,1450, 0,1455,1461,1514, 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,1446,1458,1468,1476,1480,1486,1517, 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,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, + 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, + 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, + 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, + 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0, + 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648, + 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, + 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0, + 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, + 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0, + 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142, + 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, + 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, + 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210, + 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222, + 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243, + 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389, + 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284, + 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291, + 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260, + 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343, + 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, + 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698, + 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359, + 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274, + 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304, + 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707, + 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0, + 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743, + 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770, + 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0, + 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, + 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800, + 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24, + 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714, + 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750, + 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807, + 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825, + 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829, + 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515, + 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518, + 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830, + 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, + 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, + 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, + 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0, + 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0, + 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, + 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0, + 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, + 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, + 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0, + 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, + 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, + 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929, + 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, + 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, + 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, + 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, + 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, + 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, + 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, + 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, + 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, + 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, + 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, + 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, + 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, + 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, + 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, + 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, + 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, + 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, + 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, + 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, + 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, + 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, + 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, + 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, + 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, + 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, + 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, + 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, + 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, + 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, + 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0, + 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599, + 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, - 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, - 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, - 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, - 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, - 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, - 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, - 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, - 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, - 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, - 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, - 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, - 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, - 1280, 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, 949,1134,1010, - 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, - 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, - 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, - 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, - 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, - 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, - 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, - 1514, 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,1446,1458,1468,1476,1480,1486, - 1517, 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,1489,1503,1494,1500,1508, 0, - 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, - 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, - 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, - 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, - 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, - 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, - 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, - 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, - 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, - 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, - 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, - 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, - 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, - 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, - 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, - 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, - 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, - 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, - 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, - 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, - 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, - 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, - 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, - 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, - 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, - 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, - 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, - 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, - 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, - 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, - 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, - 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, - 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, - 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, - 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, - 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, - 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, - 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, - 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, - 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, - 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, - 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, - 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, - 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, - 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, - 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, - 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, - 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, - 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, - 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, - 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, - 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, - 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, - 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, - 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, - 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, - 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, - 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, - 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, - 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, - 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, - 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, - 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, - 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, - 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, - 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, - 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, - 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, - 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, - 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, - 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, - 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, - 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, - 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, - 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, - 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, - 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, - 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, - 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, - 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, - 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, - 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, - 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, - 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, - 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, - 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, - 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, - 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, - 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, - 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, - 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, - 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950, - 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959, - 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, - 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, - 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, - 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, - 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, - 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, - 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, - 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, - 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, - 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, - 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, - 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, - 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, - 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, - 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, - 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, - 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, - 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, - 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, - 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, - 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, - 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, - 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, - 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, - 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, - 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, - 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, - 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, - 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, - 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, - 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, - 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, - 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, - 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, + 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, + 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, + 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, + 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, + 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, + 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, + 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, + 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, + 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, + 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, + 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, + 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, + 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, + 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, + 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, + 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, + 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, + 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, + 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, + 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, + 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, + 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, + 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, + 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, + 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, + 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, + 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, + 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, + 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, + 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, + 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, + 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, + 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, + 817, 818, 819, 820, 821, 935, 0, 0, }; static const int16_t _hb_ucd_i16[196] = @@ -4525,12 +4582,12 @@ _hb_ucd_i16[196] = static inline uint_fast8_t _hb_ucd_gc (unsigned u) { - return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; } static inline uint_fast8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[8612+(((_hb_ucd_u8[8068+(((_hb_ucd_u8[7624+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; + return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; } static inline unsigned _hb_ucd_b4 (const uint8_t* a, unsigned i) @@ -4540,24 +4597,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i) static inline int_fast16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9356+(((_hb_ucd_u8[9236+(((_hb_ucd_b4(9108+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9540+(((_hb_ucd_u8[9420+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; } static inline uint_fast8_t _hb_ucd_sc (unsigned u) { - return u<918000u?_hb_ucd_u8[10862+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10142+(((_hb_ucd_u8[9692+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; + return u<918000u?_hb_ucd_u8[11062+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10326+(((_hb_ucd_u8[9876+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; } static inline uint_fast16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[16764+(((_hb_ucd_u8[16382+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; + return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17068+(((_hb_ucd_u8[16686+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; } #else static const uint8_t -_hb_ucd_u8[13246] = +_hb_ucd_u8[13370] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13, @@ -4565,7 +4622,7 @@ _hb_ucd_u8[13246] = 7, 24, 21, 21, 21, 25, 26, 27, 21, 28, 29, 30, 31, 32, 33, 34, 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, 7, 35, 21, 36, - 7, 7, 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 7, 7, 7, 7, 35, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, @@ -4587,7 +4644,7 @@ _hb_ucd_u8[13246] = 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 38, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, @@ -4610,28 +4667,27 @@ _hb_ucd_u8[13246] = 34, 34,109,110,111,112,113,114,115,116,117,118, 34, 34, 34,119, 120,121,122,123,124,125,126,127, 34,128,129,111,130,131,132,133, 134,135,136,137,138,139,140,111,141,142,111,143,144,145,146,111, - 147,148,149,150,151,152,111,111,153,154,155,156,111,157,111,158, - 34, 34, 34, 34, 34, 34, 34, 34,159, 34, 34,111,111,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,160, - 34, 34, 34, 34, 34, 34, 34, 34,161,111,111,111,111,111,111,111, + 147,148,149,150,151,152,153,111,154,155,156,157,111,158,159,160, + 34, 34, 34, 34, 34, 34, 34, 34,161, 34, 34,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,162, + 34, 34, 34, 34, 34, 34, 34, 34,163,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111, - 34, 34, 34, 34,162,163,164, 34,111,111,111,111,165,166,167,168, + 34, 34, 34, 34,164,165,166, 34,111,111,111,111,167,168,169,170, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,119, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111, - 111,111,111,111,111,111,111,111, 34,169,111,111,111,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,170, 67, - 67, 67,171,172,173,130, 65,111,174,175,176,177,178,179,180,181, - 67, 67, 67, 67,182,183,111,111,111,111,111,111,111,111,184,111, - 185,111,186,111,111,187,111,111,111,111,111,111,111,111,111, 34, - 34,188,189,111,111,111,111,111,130,190,191,111, 34,192,111,111, - 67, 67,193, 67, 67,111, 67,194, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67,195,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 34,171,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,172, 67, + 67, 67,173,174,175,130, 65,111,176,177,178,179,180,181,182,183, + 67, 67, 67, 67,184,185,111,111,111,111,111,111,111,111,186,111, + 187,188,189,111,111,190,111,111,111,191,111,111,111,111,111, 34, + 34,192,193,111,111,111,111,111,130,194,195,111, 34,196,111,111, + 67, 67,197, 67, 67,111, 67,198, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67,199,111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111, - 196,111,185,185,111,111,111,111,111,111,111,111,111,111,111,111, + 200,111,188,188,111,111,111,111,111,111,111,111,111,111,111,111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, @@ -4687,7 +4743,7 @@ _hb_ucd_u8[13246] = 36, 36, 36, 36, 36, 36, 65, 43, 77, 78, 78, 43, 43, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 7, 7, 7, 85, 27, 27, 27, 84, 64, 78, 66, 36, 36, 36, 36, 36, 78, 78, 78, 77, 78, 78, 43, 43, - 43, 43, 77, 78, 78, 78, 81, 36, 86, 36, 36, 36, 36, 36, 36, 36, + 43, 43, 77, 78, 78, 78, 81, 36, 86, 82, 78, 78, 78, 78, 78, 78, 43, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 78, 79, 43, 43, 78, 78, 78, 79, 71, 61, 61, 36, 82, 27, 27, 27, 87, 27, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 77, @@ -4827,7 +4883,7 @@ _hb_ucd_u8[13246] = 36, 64, 2, 36, 36, 36, 36, 36, 36, 82, 78, 43, 43, 43, 43, 77, 81, 36, 58, 2, 56, 43, 57, 79, 7, 7, 7, 7, 7, 58, 58, 2, 90, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 78, 79, - 43, 78, 77, 43, 2, 2, 2, 43, 36, 36, 36, 36, 36, 36, 36, 64, + 43, 78, 77, 43, 2, 2, 2, 65, 36, 36, 36, 36, 36, 36, 36, 64, 77, 78, 78, 78, 78, 78, 78, 78, 36, 36, 36, 82, 78, 78, 81, 36, 36, 78, 78, 43, 43, 43, 43, 43, 36, 36, 82, 78, 43, 43, 43, 43, 78, 43, 77, 65, 36, 58, 2, 2, 7, 7, 7, 7, 7, 2, 2, 65, @@ -4848,8 +4904,10 @@ _hb_ucd_u8[13246] = 43, 43, 43, 43, 77, 43, 43, 43, 77, 43, 79, 43, 43, 43, 43, 43, 43, 43, 43, 64, 43, 43, 43, 43, 36, 36, 36, 36, 36, 78, 78, 78, 43, 77, 79, 79, 36, 36, 36, 36, 36, 64, 77, 97, 2, 2, 2, 2, - 27, 27, 84, 61, 61, 61, 53, 20,150, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 21, 43, 43, 57, 2, 2, 2, 2, 2, + 43, 82, 36, 36, 36, 36, 36, 36, 36, 36, 78, 43, 43, 43, 43, 78, + 77, 57, 2, 2, 2, 2, 2, 2, 27, 27, 84, 61, 61, 61, 53, 20, + 150, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21, + 65, 36, 36, 64, 43, 43, 43, 43, 43, 43, 57, 2, 2, 2, 2, 2, 43, 43, 43, 57, 2, 2, 61, 61, 40, 40, 89, 61, 61, 61, 61, 61, 7, 7, 7, 7, 7,167, 27, 27, 27, 87, 36, 36, 36, 36, 36, 36, 27, 27, 27, 30, 2, 2, 2, 2, 82, 78, 78, 78, 78, 78, 78, 78, @@ -4872,462 +4930,469 @@ _hb_ucd_u8[13246] = 16, 16, 16, 16, 16, 39, 16, 16, 43, 43, 43, 68, 40, 40, 40, 40, 7, 7, 7, 7, 7, 7, 7, 71, 36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 7, 7,170, - 16, 16, 43, 43, 43, 68, 40, 40, 27, 27, 27, 27, 27, 27,145, 27, - 171, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145, - 27, 27, 27, 27, 27, 27, 84, 61, 61, 61, 61, 61, 61, 25, 41, 41, - 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, - 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, - 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, - 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, - 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5, - 6, 6, 24, 24, 6, 24, 12, 12, 6, 5, 9, 21, 25, 9, 26, 12, - 11, 11, 9, 6, 5, 21, 17, 17, 17, 26, 26, 23, 23, 12, 17, 12, - 21, 12, 12, 21, 7, 21, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, - 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, - 26, 7, 21, 1, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12, - 21, 6, 10, 7, 7, 10, 23, 7, 15, 26, 13, 21, 13, 7, 15, 7, - 12, 23, 21, 26, 21, 15, 17, 7, 29, 7, 7, 22, 18, 18, 14, 14, - 14, 7, 10, 21, 17, 21, 11, 12, 5, 6, 8, 8, 8, 24, 5, 24, - 9, 24, 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, - 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6, - 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, - 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, 21, 22, - 18, 17, 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24, - 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, - 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1, - 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, 12, 17, 13, 15, - 26, 10, 10, 1, 13, 23, 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 36, 36, 36, 36, 75, 43, 43, 16, 16, 43, 43, 43, 68, 40, 40, + 27, 27, 27, 27, 27, 27,145, 27,171, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 84, 61, + 61, 61, 61, 61, 61, 25, 41, 41, 0, 0, 29, 21, 21, 21, 23, 21, + 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, + 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, + 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, + 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, + 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, + 6, 5, 9, 21, 25, 9, 26, 12, 11, 11, 9, 6, 5, 21, 17, 17, + 17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21, 7, 21, 1, 1, + 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, + 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 21, 1, 24, 7, 7, 6, + 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 10, 7, 7, 10, 23, 7, + 15, 26, 13, 21, 13, 7, 15, 7, 12, 23, 21, 26, 21, 15, 17, 7, + 29, 7, 7, 22, 18, 18, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, + 5, 6, 8, 8, 8, 24, 5, 24, 9, 24, 29, 29, 29, 1, 20, 19, + 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, + 18, 21, 21, 29, 15, 6, 18, 6, 12, 11, 9, 26, 26, 9, 26, 5, + 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, + 18, 22, 5, 12, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, + 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, + 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, + 16, 22, 16, 16, 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15, + 21, 14, 7, 15, 12, 17, 13, 15, 26, 10, 10, 1, 13, 23, 23, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, + 14, 0, 0, 0, 0, 0, 15, 0, 16, 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, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 17, 18, 19, 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, 20, 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, + 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 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, 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 35, 0, 36, 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, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, - 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, - 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, - 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, - 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, - 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, - 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, - 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, - 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, - 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, - 75, 0, 0, 76, 77, 0, 0, 78, 79, 0, 80, 62, 0, 81, 82, 0, - 0, 83, 84, 85, 0, 0, 0, 86, 0, 87, 0, 0, 51, 88, 51, 0, - 89, 0, 90, 0, 0, 0, 79, 0, 0, 0, 91, 92, 0, 93, 94, 95, - 96, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 97, 98, 0, 0, 0, - 0, 99,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,101, 0, 0, - 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103,104, 0, 0,105, - 0, 0, 0, 0, 0, 0,106, 0, 0, 0,100, 0, 0, 0, 0, 0, - 107,108, 0, 0, 0, 0, 0, 0, 0,109, 0,110, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, - 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, - 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, - 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31, 0, 0, - 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0, 33, 36, - 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, - 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44, 0, 0, - 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, - 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, - 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58, 0, 0, - 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63, 0, 0, - 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70, 71, 72, - 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79, 0, 0, - 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82, 0, 83, - 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78, 0, 0, - 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0, 0, 0, - 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0, 0, 0, - 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94, 95, 0, - 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,100, 93, - 0, 0,101, 0, 0, 0, 84, 0, 0,102, 0, 0, 0,103,104, 0, - 0,105,106, 0, 0, 0, 0, 0, 0,107, 0, 0,108, 0, 0, 0, - 0,109, 33, 0,110,111,112, 35, 0, 0,113, 0, 0, 0,114, 0, - 0, 0, 0, 0, 0,115, 0, 0,116, 0, 0, 0, 0,117, 88, 0, - 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,118, 0, 0, 0, 0,119, - 0, 0,120, 0, 0, 0, 0,118, 0, 0, 0, 0, 0,121, 0, 0, - 0,122, 0, 0, 0,123, 0,124, 0, 0, 0, 0,125,126,127, 0, - 128, 0,129, 0, 0, 0,130,131,132, 0, 0, 0, 35, 0, 0, 0, - 133, 0, 0,134, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, - 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, - 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, - 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, - 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, - 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, - 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, - 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, - 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, - 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, - 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, - 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, - 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, - 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, - 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87, 0, 55, - 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, - 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4, 90, 8, - 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, - 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0, 0, 0, - 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102, 0, 0, - 103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, - 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,105,106, - 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12, 84, 0, - 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61, 0,110, - 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0,111, 14, 52,112, 41, - 0, 0, 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, - 0, 0, 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, - 78, 55, 0, 38, 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0, - 0, 0, 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, - 0, 79, 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 8, 91, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, + 40, 41, 42, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, + 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, + 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, + 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, + 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, + 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, + 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, + 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, + 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, + 0, 0, 74, 0, 0, 0, 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, + 80, 0, 81, 62, 0, 82, 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, + 0, 88, 0, 0, 51, 89, 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, + 0, 0, 92, 93, 0, 94, 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, + 0, 0, 0, 98, 99, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 0, + 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103, 0, 0, + 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 0, 0,107, + 0, 0, 0, 0, 0, 0,108, 0,109, 0,102, 0, 0, 0, 0, 0, + 110,111, 0, 0, 0, 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, + 0,113, 0,114, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, + 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, + 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, + 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, + 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, + 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, + 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, + 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, + 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, + 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, + 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, + 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, + 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, + 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, + 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, + 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, + 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, + 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, + 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, + 98, 0, 0, 0, 99, 0, 0, 0, 0,100,101, 93, 0, 0,102, 0, + 0, 0, 84, 0, 0,103, 0, 0, 0,104,105, 0, 0,106,107, 0, + 0, 0, 0, 0, 0,108, 0, 0,109, 0, 0, 0, 0,110, 33, 0, + 111,112,113, 35, 0, 0,114, 0, 0, 0,115, 0, 0, 0, 0, 0, + 0,116, 0, 0,117, 0, 0, 0, 0,118, 88, 0, 0, 0, 0, 0, + 57, 0, 0, 0, 0, 52,119, 0, 0, 0, 0,120, 0, 0,121, 0, + 0, 0, 0,119, 0, 0,122, 0, 0, 0, 0, 0, 0,123, 0, 0, + 0,124, 0, 0, 0,125, 0,126, 0, 0, 0, 0,127,128,129, 0, + 130, 0,131, 0, 0, 0,132,133,134, 0, 77, 0, 0, 0, 0, 0, + 35, 0, 0, 0,135, 0, 0, 0,136, 0, 0,137, 0, 0,138, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, + 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, + 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, + 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, + 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, + 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, + 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, + 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, + 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, + 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, + 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, + 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, + 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, + 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, + 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, + 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, + 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, + 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, + 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58, 81, 99, + 100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, + 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50, 0, 0, + 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68, 61, 0, + 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0, 0, 0, + 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, + 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0, 0, 0, + 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0, 62, 0, + 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, + 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38, + 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0, 55, 0, + 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, + 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,116, 0, 0, 0, 0, 0, 0,117, 0,118, 119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0, 0, 0, - 0, 1, 4,122, 0, 0, 0, 1,123, 0, 0, 0, 0, 0,230,230, - 230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202, - 202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220, - 220,220,220,230,230,230,230,240,230,220,220,220,230,230,230,220, - 220, 0,230,230,230,220,220,220,220,230,232,220,220,230,233,234, - 234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230, - 220,230,230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, - 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, - 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, - 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, - 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230, - 220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230, - 230,230,230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, - 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230, - 220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, - 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107, - 107,107,118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, - 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0, - 130,130,130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0, - 220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, - 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, - 0,220,230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, - 7, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230, - 230,230,230,230,232,228,228,220,218,230,233,220,230,220,230,230, - 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0, - 218,228,232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0, - 230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1, - 220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, - 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, - 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216, - 216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 33, 17, 49, - 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 0, 1, 0, 0, 0,123, 4,122, 0, 0, 0, 1,124, 0, 0, 0, + 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,220,220, + 220,220,220,202,202,220,220,220,220,202,202,220,220,220, 1, 1, + 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,220,220, + 230,230,230,220,220, 0,230,230,230,220,220,220,220,230,232,220, + 220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220, + 230,230,230,230,220,230,230,230,222,220,230,230,220,220,230,222, + 228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, + 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, + 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230, + 230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0, + 220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220, + 230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230, + 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,230,220, + 220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0, 0, 9, + 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, 0, 84, + 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,103,103, + 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,220,220, + 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,132, 0, + 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0, + 230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, + 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, + 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0, 0, 0, + 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234, + 214,220,202,230,230,230,230,230,232,228,228,220,218,230,233,220, + 230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, + 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, 0, 0, + 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, + 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0, + 230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, + 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226, + 216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,230,230, + 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, + 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, + 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, + 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 24, 3, 3, 3, 3, + 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, + 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, + 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, + 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, + 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, + 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, + 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, + 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, + 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, + 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, + 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, + 0, 3, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, + 0, 0, 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, + 8, 9, 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, + 17, 0, 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, + 0, 0, 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, + 0, 0, 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, + 29, 30, 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, + 5, 0, 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, + 34, 1, 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, + 40, 0, 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, + 1, 8, 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, + 1, 44, 0, 0, 0, 45, 8, 9, 1, 0, 0, 0, 8, 21, 21, 21, + 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, + 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 3, 3, 3, 3, 3, 3, 3, 15, 3, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, - 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, 3, 3, - 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, 3, 14, - 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, 3, 3, - 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3, 3, 3, - 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0, 0, 1, - 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, - 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, - 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, 17, 18, - 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, 19, 28, - 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 19, - 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, 40, 19, - 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, 0, 32, - 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, 48, 49, - 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, 0, 0, - 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57, 0, 0, - 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59, 14, 0, - 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60, 61, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3, 0, 4, - 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0, 0, 8, - 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 0, 0, - 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0, 0, 18, - 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0, 0, 1, - 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0, 1, 0, - 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20, 1, 1, - 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9, 0, 1, - 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21, 9, 36, - 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0, 0, 0, - 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21, 21, 21, - 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9, 0, 0, - 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45, 8, 9, - 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1, 8, 21, - 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 3, 3, 3, 3, 3, 3, - 3, 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, - 18, 17, 19, 20, 21, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 25, 25, 26, 27, - 28, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 31, - 31, 31, 31, 54, 55, 55, 56, 31, 31, 31, 31, 31, 31, 31, 57, 58, + 17, 17, 18, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 17, 17, 18, 17, 19, 20, 21, 22, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 25, 25, 26, 27, 28, 29, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 59, 60, 31, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 63, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 65, 66, 67, 31, 31, 31, 31, 68, 31, 31, 31, 31, 31, - 31, 31, 31, 69, 70, 71, 17, 17, 72, 73, 31, 74, 75, 76, 31, 77, - 78, 31, 79, 80, 17, 81, 17, 17, 17, 17, 31, 31, 23, 23, 23, 23, - 23, 23, 31, 31, 31, 31, 31, 31, 23, 82, 31, 31, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 83, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 84, 0, 0, 1, - 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, - 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 11, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 19, 27, - 28, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, - 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 42, 43, 44, 44, 45, 46, - 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 50, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 51, - 60, 61, 62, 63, 64, 65, 66, 7, 67, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 7, 4, 4, 4, 4, 77, 77, 77, 77, 78, 79, 80, 81, - 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 85, 85, - 0, 0, 0, 0, 86, 87, 88, 88, 89, 90, 48, 91, 0, 0, 92, 92, - 92, 92, 92, 93, 94, 95, 96, 97, 98, 47, 99,100,101,102, 0,103, - 104,105, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 0,106,106,106,106,106,106,106,106,106,106,106,107, - 108,108,108,108,108, 11,109,110,111, 4,112, 4,113,114,115,116, - 117,118,119,120,121,122,123,124,125,126, 50,127, 47, 47, 47, 47, - 47, 47, 47, 47,128,128,128,128,128,128,128,128,128,128,128,128, - 92, 92, 92, 92, 92, 92, 92, 92,129,130, 19, 19, 19, 19, 19, 19, - 131, 19, 19, 19,132,133, 19,134,135,136,137,101,138,138,138,138, - 0, 77,139,140,128,128,141,142,143,144,145,146,147,148,149,150, - 151,152,153,153,154,154,154,154,154,154, 4, 4,155,156,157,158, - 159,160,161,162,163,164,165,166,167,168,169,169,170,170,171,171, - 172,172,128,128, 19, 19,173,173,174,175,176,177,178,178,179,180, - 181,182,183,184,185,185,186,187,188,189,128,128,190,190,191,191, - 128,128,192,192,193,194,195,195,196,196,128,128,197,197,198,198, - 199,199,200,200,201,202,203,204,128,128,128,128,205,206,207,207, - 208,209,210,210,128,128,211,211,128,128,212, 34,213,213,213,213, - 213,213,213,213,213,213,213,213,213,213,128,128,128,128,128,128, - 128,128,214,214,215,215,215,215,215,215,215,215,215,215,128,128, - 128,128,128,128,216,216,216,216,216,216,216,216,216,216,128,128, - 128,128,128,128,110,110,110,110,110,110,110,110,110,217,218,219, - 220,220,220,220,221,221,221,221,222,222,222,223,224,224,224,224, - 224,224,224,224,224,224,224,224,225,225,225,225,225,225,225,225, - 224,224,128,128,128,128,128,128,128,128,104,104,226,227,227,227, - 228,229,230,230,230,230,230,230,128,128,128,128,231,231,232, 0, - 128,128,128,128,128,128,128,128, 7,233, 0, 0, 0, 0, 0, 0, - 0,234,235, 0, 77, 77, 0, 0, 0, 0,128,128,236,236,236,236, - 236,236,236,236,236,236,236,236,128,128,128,128,128,128,128,128, - 4, 4,128,128, 86, 86,128,128,237,237,128,128,128,128,238,239, - 128,128,128,128,128,128,128,128,128,128, 48, 48,240,240,240,240, - 241,241,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19, - 128,128,128,128,242, 0,128,128, 0, 0, 0, 0, 92, 92,128,128, - 128,128,128,128, 92, 92, 92, 92, 92, 92,128,128, 0, 0,128,128, - 7, 7, 7, 7, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, - 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, - 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 12, 11, - 13, 13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16, - 16, 17, 18, 18, 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, 21, 24, - 21, 21, 21, 21, 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, 21, 21, - 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 26, 21, - 21, 21, 31, 21, 32, 32, 32, 32, 32, 33, 34, 32, 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, 45, 44, 44, 44, 44, 46, 46, 46, 46, 47, 47, 47, 47, - 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, - 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, - 55, 55, 55, 55, 56, 56, 57, 57, 57, 57, 58, 57, 59, 59, 60, 61, - 62, 62, 63, 63, 64, 64, 64, 64, 65, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69, - 69, 69, 64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71, 8, - 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, - 75, 76, 76, 76, 13, 50, 50, 50, 73, 77, 78, 79, 4, 4, 80, 4, - 4, 81, 82, 83, 4, 4, 4, 84, 11, 11, 11, 11, 85, 0, 0, 0, - 0, 0, 0, 86, 0, 4, 0, 0, 0, 8, 8, 8, 0, 0, 87, 88, - 89, 0, 4, 4, 6, 0, 0, 0, 90, 90, 90, 90, 91, 91, 91, 91, - 91, 91, 4, 4, 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, 93, 93, - 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, 94, 0, 95, 0, 96, 97, - 98, 99, 99, 99, 99,100,101,102,102,102,102,103,104,104,104,105, - 52, 0,104,104, 0, 0, 0,102, 52, 52, 0, 0, 0, 0, 52,106, - 0,102,102,107,102,102,102,102,102,108, 0, 0,109,109,109,109, - 109,110,110,110,111,111,111,111, 13, 13,112,112,112,112,112,112, - 0, 0,113, 4,114, 4, 4, 4,115,115,115, 0,116,116,116,116, - 117,117,117,117,117,117, 32, 32,118,118,119,120,120,120, 52, 52, - 121,121,121,121,122,121, 49, 49,123,123,123,123,123,123, 49, 49, - 124,124,124,124,124,124,125,125, 53, 53, 53, 4, 4,126,127, 54, - 125,125,125,125,128,128,128,128, 4,129, 18, 18, 18, 21, 21, 21, - 21, 21, 21,130, 8, 0,131, 0, 0, 0, 0, 21, 21, 21, 21,132, - 0, 0, 1, 2, 1, 2,133,101,102,134, 52, 52,135,135,135,135, - 11, 0, 11, 11, 11, 0, 0,136,137,137,138,138,138,138,139, 0, - 140,140,140,141,141,142,142,142,143,143,144,144,144,144,144,144, - 145,145,145,145,145,146,146,146,147,147,147,148,148,148,148,148, - 149,149,149,150,150,150,150,151,151,151,151,151,152,152,152,152, - 153,153,153,153,154,154,155,155,156,156,156,156,156,156,157,157, - 158,158,159,159,159,159,159,159,160,160,161,161,161,161,161,161, - 162,162,162,162,162,162,163,163,164,164,164,164,165,165,165,165, - 166,166,166,166,167,167,168,168,169,169,169,169,170,170,170,170, - 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,175, - 175,175,175,176,176,176,176,177,177,177,178,178,179,179,179,179, - 180,180,180,180,180,181,181,181,182,182,182,182,182,183,183,183, - 184,184,184,184,184,184,185, 43,186,186,186,186,187,187,187,188, - 188,188,188,188,189,189,189,190,189,189,189,189,191,191,191,191, - 192,192,192,192,193,193,193,193,194,194,194,194,194,194, 66, 66, - 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198, - 199,199,199,199,200,200,200,200,201,201,201,201,201,202,202,202, - 202,202,202, 55,203,203,203,203,204,204,204,204,204,204,204,205, - 205,205,205,205,206,206,206,206,206,206,207,207,207,207,207,207, - 208,208,208,208,110,110,110,110,209,209,209,209,210,210,210,210, - 211,211,211,211,212,212,212,212,213,213,213,214,214,214,214,214, - 214,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218, - 218,218,219, 94,220,220,220,220,221,221,221,221,222, 99, 99, 99, - 99, 99, 99, 99, 99, 99,102,102,102, 99,223,224,224,224,224,224, - 225,225,225,225,225,225, 0, 0, 8, 0, 0, 0, 0, 0,226,227, - 228, 0,229, 0,230,230,230,230,231,231,231,231,232,232,232,232, - 233,233,233,233,234,234,234,234,235,235,235,235,236, 0, 0, 0, - 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 0, 0, 0, 4, 0, - 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 0, 2, 5, 6, 0, - 7, 7, 7, 7, 8, 9, 8, 10, 8, 11, 8, 8, 8, 8, 8, 8, - 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14, 16, 17, 17, 17, - 17, 17, 17, 17, 18, 19, 19, 19, 19, 19, 19, 19, 20, 21, 20, 22, - 20, 20, 23, 23, 20, 20, 20, 20, 22, 20, 24, 7, 7, 25, 20, 20, - 26, 20, 20, 20, 20, 20, 20, 21, 27, 27, 27, 27, 28, 28, 28, 28, - 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 20, 20, 20, - 33, 33, 33, 33, 34, 35, 33, 33, 33, 36, 33, 33, 37, 37, 37, 37, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 52, 53, 31, 31, 31, 31, 54, 55, 55, 56, 31, + 31, 31, 31, 31, 31, 31, 57, 58, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 59, 60, 31, 61, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 64, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 65, 66, 67, 31, 31, + 31, 31, 68, 31, 31, 31, 31, 31, 31, 31, 31, 69, 70, 71, 17, 17, + 72, 73, 31, 74, 75, 76, 77, 78, 79, 31, 80, 81, 17, 82, 17, 17, + 17, 17, 31, 31, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, + 23, 83, 31, 31, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 84, 0, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, + 4, 5, 6, 7, 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 6, + 7, 8, 9, 10, 11, 11, 12, 11, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 19, 27, 28, 29, 30, 30, 31, 31, 32, 32, + 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 40, 41, 41, + 42, 42, 42, 43, 44, 44, 45, 46, 47, 47, 47, 47, 48, 48, 48, 48, + 48, 48, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53, + 54, 55, 56, 56, 57, 58, 59, 51, 60, 61, 62, 63, 64, 65, 66, 7, + 67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 7, 4, 4, 4, 4, + 77, 77, 77, 77, 78, 79, 80, 81, 82, 83, 84, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 85, 85, 85, 85, 0, 0, 0, 0, 86, 87, 88, 88, + 89, 90, 48, 91, 0, 0, 92, 92, 92, 92, 92, 93, 94, 95, 96, 97, + 98, 47, 99,100,101,102, 0,103,104,105, 0, 0, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0,106,106,106,106, + 106,106,106,106,106,106,106,107,108,108,108,108,108, 11,109,110, + 111, 4,112, 4,113,114,115,116,117,118,119,120,121,122,123,124, + 125,126, 50,127, 47, 47, 47, 47, 47, 47, 47, 47,128,128,128,128, + 128,128,128,128,128,128,128,128, 92, 92, 92, 92, 92, 92, 92, 92, + 129,130, 19, 19, 19, 19, 19, 19,131, 19, 19, 19,132,133, 19,134, + 135,136,137,101,138,138,138,138, 0, 77,139,140,128,128,141,142, + 143,144,145,146,147,148,149,150,151,152,153,153,154,154,154,154, + 154,154, 4, 4,155,156,157,158,159,160,161,162,163,164,165,166, + 167,168,169,169,170,170,171,171,172,172,128,128, 19, 19,173,174, + 175,176,177,178,179,179,180,181,182,183,184,185,186,186,187,188, + 189,190,128,128,191,191,192,192,128,128,193,193,194,195,196,196, + 197,197,128,128,198,198,199,199,200,200,201,201,202,203,204,205, + 28, 28,128,128,206,207,208,208,209,210,211,211,128,128,212,212, + 213,213,214, 34,215,215,215,215,215,215,215,215,215,215,215,215, + 215,215,128,128,128,128,128,128,128,128,216,216,217,217,217,217, + 217,217,217,217,217,217,128,128,128,128,128,128,218,218,218,218, + 218,218,218,218,218,218,128,128,128,128,128,128,110,110,110,110, + 110,110,110,110,110,219,220,221,222,222,222,222,223,223,223,223, + 224,224,224,225,226,226,226,226,226,226,226,226,226,226,226,226, + 227,227,227,227,227,227,227,227,226,226,128,128,128,128,128,128, + 128,128,104,104,228,229,229,229,230,231,232,232,232,232,232,232, + 128,128,128,128,233,233,234, 0,128,128,128,128,128,128,128,128, + 7,235, 0, 0, 0, 0, 0, 0, 0,236,237, 0, 77, 77, 0, 0, + 0, 0,128,128,238,238,238,238,238,238,238,238,238,238,238,238, + 128,128,128,128,128,128,128,128, 4, 4,128,128,239, 11, 11, 11, + 240,240,128,128,128,128,241,242,128,128,128,128,128,128,243,243, + 128,128,128,128,128,128,128,128,128,128, 48, 48,244,244,244,244, + 245,245,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19, + 128,128,128,128,246, 0,128,128, 0, 0, 0, 0, 92, 92,128,128, + 128,128,128,128, 0, 0,128,128, 7, 7, 7, 7, 0, 0, 0, 0, + 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, + 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9, + 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 14, 13, 13, 13, + 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18, 18, 18, 18, 18, + 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21, 21, 25, 21, 21, + 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27, 28, 28, 28, 28, + 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 31, 21, 32, 32, 32, 32, + 32, 33, 34, 32, 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, 46, 46, 46, 47, 48, 48, 48, 48, 49, 49, 49, 49, - 49, 50, 51, 49, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 53, - 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, - 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 62, 63, 63, 63, 63, - 64, 64, 64, 64, 64, 65, 0, 0, 66, 66, 66, 66, 67, 67, 67, 67, - 68, 68, 68, 68, 69, 70, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, - 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, - 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, - 81, 81, 81, 81, 82, 7, 7, 7, 83, 7, 84, 85, 0, 84, 86, 0, - 2, 87, 88, 2, 2, 2, 2, 89, 90, 87, 91, 2, 2, 2, 92, 2, - 2, 2, 2, 93, 0, 0, 0, 86, 1, 0, 0, 94, 0, 95, 96, 0, - 4, 0, 0, 0, 0, 0, 0, 4, 97, 97, 97, 97, 98, 98, 98, 98, - 13, 13, 13, 13, 99, 99, 99, 99,100,100,100,100, 0,101, 0, 0, - 102,100,103,104, 0, 0,100, 0,105,106,106,106,106,106,106,106, - 106,106,107,105,108,109,109,109,109,109,109,109,109,109,110,108, - 111,111,111,111,112, 55, 55, 55, 55, 55, 55,113,109,109,109,110, - 109,109, 0, 0,114,114,114,114,115,115,115,115,116,116,116,116, - 117,117,117,117, 96, 2, 2, 2, 2, 2, 94, 2,118,118,118,118, - 119,119,119,119,120,120,120,120,121,121,121,121,121,121,121,122, - 123,123,123,123,124,124,124,124,124,124,124,125,126,126,126,126, - 127,127,127,127,128,128,128,128, 2, 2, 3, 2, 2,129,130, 0, - 131,131,131,131,132, 17, 17, 18, 20, 20, 20,133, 7, 7, 7,134, - 20, 20, 20, 23, 0,135,109,109,109,109,109,136,137,137,137,137, - 0, 0, 0,138,139,139,139,139,140,140,140,140, 84, 0, 0, 0, - 141,141,141,141,142,142,142,142,143,143,143,143,144,144,144,144, - 145,145,145,145,146,146,146,146,147,147,147,147,148,148,148,148, - 149,149,149,149,150,150,150,150,151,151,151,151,152,152,152,152, - 153,153,153,153,154,154,154,154,155,155,155,155,156,156,156,156, - 157,157,157,157,158,158,158,158,159,159,159,159,160,160,160,160, - 161,161,161,161,162,162,162,162,163,163,163,163,164,164,164,164, - 165,165,165,165,166,166,166,166,167,167,167,167,168,168,168,168, + 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44, + 46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49, + 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 53, 53, 53, 53, + 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57, + 57, 57, 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64, + 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 67, 67, 67, 67, + 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 8, 72, 72, 72, 72, 73, 73, 73, 73, + 74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50, + 73, 77, 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, 4, 4, 84, + 11, 11, 11, 11, 85, 0, 0, 0, 0, 0, 0, 86, 0, 4, 0, 0, + 0, 8, 8, 8, 0, 0, 87, 88, 89, 0, 4, 4, 6, 0, 0, 0, + 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 4, 4, 92, 92, 92, 92, + 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 13, 13, 94, 94, 94, 94, + 94, 94, 94, 0, 95, 0, 96, 97, 98, 99, 99, 99, 99,100,101,102, + 102,102,102,103,104,104,104,105, 52, 0,104,104, 0, 0, 0,102, + 52, 52, 0, 0, 0, 0, 52,106, 0,102,102,107,102,102,102,102, + 102,108, 0, 0,109,109,109,109,109,110,110,110,111,111,111,111, + 13, 13,112,112,112,112,112,112, 0, 0,113, 4,114, 4, 4, 4, + 115,115,115, 0,116,116,116,116,117,117,117,117,117,117, 32, 32, + 118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, 49, 49, + 123,123,123,123,123,123, 49, 49,124,124,124,124,124,124,125,125, + 53, 53, 53, 4, 4,126,127, 54,125,125,125,125,128,128,128,128, + 4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21,130, 8, 0,131, 0, + 0, 0, 0, 21, 21, 21, 21,132, 0, 0, 1, 2, 1, 2,133,101, + 102,134, 52, 52,135,135,135,135, 11, 0, 11, 11, 11, 0, 0,136, + 137,137,138,138,138,138,139, 0,140,140,140,141,141,142,142,142, + 143,143,144,144,144,144,144,144,145,145,145,145,145,146,146,146, + 147,147,147,148,148,148,148,148,149,149,149,150,150,150,150,151, + 151,151,151,151,152,152,152,152,153,153,153,153,154,154,155,155, + 156,156,156,156,156,156,157,157,158,158,159,159,159,159,159,159, + 160,160,161,161,161,161,161,161,162,162,162,162,162,162,163,163, + 164,164,164,164,165,165,165,165,166,166,166,166,167,167,168,168, 169,169,169,169,170,170,170,170,171,171,171,171,172,172,172,172, - 173,173,173,173,174,174,174,174,175,175,175,175,176,176,176,176, - 177,177,177,177,178,178,178,178,179,179,179,179,180,180,180,180, - 181,181,181,181,182,182,182,182,183,183,183,183,184,184,184,184, - 185,185,185,185,186, 45, 45, 45,187,187,187,187,188,188,188,188, - 189,189,189,189,190,190,190,190,190,190,191,190,192,192,192,192, - 193,193,193,193,194,194,194,194,195,195,195,195,196,196,196,196, + 173,173,173,173,173,173,173,174,175,175,175,176,176,176,176,177, + 177,177,177,178,178,178,179,179,180,180,180,180,181,181,181,181, + 181,182,182,182,183,183,183,183,183,184,184,184,185,185,185,185, + 185,185,186, 43,187,187,187,187,188,188,188,189,189,189,189,189, + 190,190,190,191,190,190,190,190,192,192,192,192,193,193,193,193, + 194,194,194,194,195,195,195,195,195,195, 66, 66,196,196,196,196, 197,197,197,197,198,198,198,198,199,199,199,199,200,200,200,200, - 201,201,201,201,202,202,202,202,203,203,203,203,204,204,204,204, - 205,205,205,205,206,206,206,206,207,207,207,207,208,208,208,208, - 209,209,209,209,210,210,210,210,211,211,211,211,212,212,212,212, - 213,213,213,213,214,214,214,214,215,215,215,215,216,216,216,216, - 217,217,217,217,218,218,218,218,219,219,219,219,220,221,221,221, - 222,222,222,222,221,221,221,221,223,106,106,106,106,109,109,109, - 224,224,224,224,225,225,225,225, 0,226, 86, 0, 0, 0,226, 7, - 82,138, 7, 0, 0, 0,227, 86,228,228,228,228,229,229,229,229, - 230,230,230,230,231,231,231,231,232,232,232,232,233,233,233,233, - 234, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0, 26, 26, - 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, 9, - 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, - 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 14, 14, 14, - 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, - 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, 3, - 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64, 90, 90, 90, 90, - 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7, 7, 1, 1, 1, - 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 11, 11, 11, 11, - 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, - 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, 24, 24, 24, 24, - 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25, 25, 0, 0, 0, - 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 0, - 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29, 28, 28, 28, 28, - 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, - 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0, 43, 43, 43, 43, - 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0, 32, 0, 32, 32, - 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52, 58, 58, 58, 58, - 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62, 76, 76, 76, 76, - 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73, 1, 1, 1, 0, - 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, - 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19, - 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, 0, 0, 0, 19, - 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 56, 56, 56, 56, - 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13, 0, 13, 13, 13, - 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15, 15, 15, 15, 15, - 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, - 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0, 39, 39, 39, 39, - 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 60, 60, 60, 60, - 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69, 69, 69, 0, 69, - 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0, 68, 68, 68, 68, - 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19, 19, 19, 0, 0, - 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0, 1, 1, 6, 6, - 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49, 0, 1, 1, 1, - 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42, 41, 41, 41, 41, - 118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59, 40, 40, 40, 40, - 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,106,106,106,106, - 104,104,104,104,161,161,161,161,110,110,110,110, 47, 47, 47, 47, - 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128,128,128, - 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, 97, 97, - 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112,112,112, - 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122,122,122, - 89, 89, 89, 89,130,130,130,130,144,144,144,144,156,156,156,156, - 147,147,147,147,148,148,148,148,158,158,158,158,153,153,153,153, - 149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, - 96, 96, 96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36, - 108,108,108,108,129,129,129,129,109,109,109,109,107,107,107,107, - 107,107,107, 1,137,137,137,137,124,124,124,124,123,123,123,123, - 114,114,114,114,102,102,102,102,126,126,126,126,142,142,142,142, - 125,125,125,125,154,154,154,154,150,150,150,150,141,141,141,141, - 140,140,140,140,121,121,121,121,133,133,133,133,134,134,134,134, - 138,138,138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63, + 201,201,201,201,202,202,202,202,202,203,203,203,203,203,203, 55, + 204,204,204,204,205,205,205,205,205,205,205,206,206,206,206,206, + 207,207,207,207,207,207,208,208,208,208,208,208,209,209,209,209, + 210,210,210,210,110,110,110,110,211,211,211,211,212,212,212,212, + 213,213,213,213,214,214,214,214,215,215,215,216,216,216,216,216, + 216,217,217,217,218,218,218,218,219,219,219,219,220,220,220,220, + 220,220,221, 94,222,222,222,222,223,223,223,223,224, 99, 99, 99, + 99, 99, 99, 99, 99, 99,102,225, 99,226,102,227,227,227,227,227, + 228,228,228,228,228,228, 0, 0, 8, 0, 0, 0, 0, 0,229,230, + 231, 0,232, 0,233,233,233,233, 91, 91, 91, 13,234,234,234,234, + 235,235,235,235,236,236,236,236,237,237,237,237,238,238,238,238, + 239,239,239,239,240, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, + 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, + 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10, + 8, 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14, + 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19, + 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20, + 22, 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21, + 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, + 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33, + 33, 36, 33, 33, 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, 46, 46, 46, 47, + 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52, + 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56, + 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, + 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0, + 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71, + 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, + 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, + 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7, + 83, 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89, + 90, 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86, + 1, 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4, + 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99, + 100,100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0,100, 0, + 105,106,106,106,106,106,106,106,106,106,107,105,108,109,109,109, + 109,109,109,109,109,109,110,108,111,111,111,111,112, 55, 55, 55, + 55, 55, 55,113,109,109,109,110,109,109, 0, 0,114,114,114,114, + 115,115,115,115,116,116,116,116,117,117,117,117, 96, 2, 2, 2, + 2, 2, 94, 2,118,118,118,118,119,119,119,119,120,120,120,120, + 121,121,121,121,121,121,121,122,123,123,123,123,124,124,124,124, + 124,124,124,125,126,126,126,126,127,127,127,127,128,128,128,128, + 2, 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, 17, 18, + 20, 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109, + 109,109,109,136,137,137,137,137, 0, 0, 0,138,139,139,139,139, + 140,140,140,140, 84, 0, 0, 0,141,141,141,141,142,142,142,142, + 143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146, + 147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150, + 151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154, + 155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158, + 159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162, + 163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166, + 167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170, + 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174, + 174,174,174,175,176,176,176,176,177,177,177,177,178,178,178,178, + 179,179,179,179,180,180,180,180,181,181,181,181,182,182,182,182, + 183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186, + 187, 45, 45, 45,188,188,188,188,189,189,189,189,190,190,190,190, + 191,191,191,191,191,191,192,191,193,193,193,193,194,194,194,194, + 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198, + 199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202, + 203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206, + 207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210, + 211,211,211,211,212,212,212,212,213,213,213,213,214,214,214,214, + 215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218, + 219,219,219,219,220,220,220,220,221,221,221,221,222,223,223,223, + 224,224,224,224,223,223,223,223,225,106,106,106,226,106,106,106, + 106,227,109,109,228,228,228,228,229,229,229,229, 0,230, 86, 0, + 0, 0,230, 7, 82,138, 7, 0, 0, 0,231, 86,232,232,232,232, + 233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236, + 237,237,237,237,238,238,238,238,239, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, + 19, 0, 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, + 55, 55, 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, + 4, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, + 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, + 1, 1, 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, + 64, 64, 64, 64, 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, + 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, + 5, 5, 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, + 22, 22, 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, + 36, 36, 36, 36, 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, + 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, + 8, 8, 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, + 29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, + 35, 35, 35, 0, 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, + 44, 0, 0, 0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, + 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, + 52, 52, 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, + 62, 62, 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, + 73, 73, 73, 73, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, + 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, + 19, 19, 19, 9, 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, + 27, 27, 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, + 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, + 0, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, + 12, 12, 12, 0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, + 79, 79, 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, + 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, + 84, 84, 84, 0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, + 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, + 3, 3, 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, + 49, 49, 49, 49, 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, + 42, 42, 42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, + 59, 59, 59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50, + 135,135,135,135,106,106,106,106,104,104,104,104,161,161,161,161, + 110,110,110,110, 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120, + 116,116,116,116,128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, + 98, 98, 98, 98, 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88, + 117,117,117,117,112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83, + 82, 82, 82, 82,122,122,122,122, 89, 89, 89, 89,130,130,130,130, + 144,144,144,144,156,156,156,156,156, 3, 3, 3,147,147,147,147, + 148,148,148,148,158,158,158,158,153,153,153,153,149,149,149,149, + 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96, 96, 96, + 111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108,108,108, + 129,129,129,129,109,109,109,109,107,107,107,107,107,107,107, 1, + 137,137,137,137,124,124,124,124,123,123,123,123,114,114,114,114, + 102,102,102,102,126,126,126,126,142,142,142,142,125,125,125,125, + 154,154,154,154,150,150,150,150,141,141,141,141,140,140,140,140, + 121,121,121,121,133,133,133,133,134,134,134,134,138,138,138,138, + 143,143,143,143,145,145,145,145,163,163,163,163, 63, 63, 63, 63, 157,157,157,157, 80, 80, 80, 80,127,127,127,127,115,115,115,115, 159,159,159,159,103,103,103,103,119,119,119,119,146,146,146,146, 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136, - 17, 15, 15, 15,139,139,139,139,105,105,105,105, 0, 0, 0, 1, - 0, 0, 1, 1,131,131,131,131,151,151,151,151,160,160,160,160, - 152,152,152,152,113,113,113,113,132,132,132,132, 15, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, - 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, + 17, 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139, + 105,105,105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131, + 151,151,151,151,160,160,160,160,152,152,152,152,164,164,164,164, + 113,113,113,113,132,132,132,132, 15, 0, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, + 9, 14, 9, 9, 15, 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, 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, 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, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 18, 19, 20, 9, 21, 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, 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, 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, - 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 22, 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, 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, 9, @@ -5336,60 +5401,60 @@ _hb_ucd_u8[13246] = 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, 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, 9, 9, 23, 24, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, - 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, + 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, + 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, - 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, - 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, + 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, + 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, + 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, + 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, - 66, 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, 67, 68, - 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, + 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0, + 111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0, - 109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0, - 116, 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,117, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119, + 120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,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, 0, 0, 0,158,159,160,161, 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,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, 0, 0, 0,158, - 159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0, - 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169, + 170, 0, 0, 0, 0,171,172, 0, 0, 0,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, 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, 1, 2, 3, 4, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, }; static const uint16_t -_hb_ucd_u16[4888] = +_hb_ucd_u16[4920] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -5456,39 +5521,41 @@ _hb_ucd_u16[4888] = 359, 47, 47, 360, 145, 66, 47, 361, 47, 362, 145, 145, 363, 47, 364, 66, 47, 47, 47, 365, 47, 366, 47, 366, 47, 365, 144, 145, 145, 145, 145, 145, 9, 9, 9, 9, 11, 11, 11, 367, 47, 47, 368, 160, 160, 160, 160, 160, - 145, 145, 145, 145, 145, 145, 145, 145, 47, 47, 369, 47, 47, 47, 47, 47, + 145, 145, 145, 145, 145, 145, 145, 145, 47, 47, 369, 47, 47, 47, 47, 143, 47, 362, 370, 47, 60, 371, 66, 47, 372, 66, 66, 47, 373, 145, 47, 47, 374, 47, 47, 360, 375, 376, 377, 378, 180, 47, 47, 379, 380, 47, 47, 160, 97, 47, 381, 382, 383, 47, 47, 384, 180, 47, 47, 385, 386, 387, 388, 145, - 47, 47, 389, 390, 32, 32, 32, 32, 47, 47, 365, 47, 47, 391, 172, 160, + 47, 47, 389, 390, 359, 32, 32, 32, 47, 47, 365, 47, 47, 391, 172, 160, 92, 47, 47, 113, 392, 393, 394, 32, 47, 47, 47, 395, 396, 397, 47, 47, 47, 47, 47, 398, 399, 160, 160, 160, 47, 47, 400, 401, 402, 403, 32, 32, 47, 47, 47, 404, 405, 160, 66, 66, 47, 47, 406, 407, 160, 160, 160, 160, 47, 143, 408, 409, 47, 47, 47, 47, 47, 47, 389, 410, 66, 66, 66, 66, 9, 9, 9, 9, 11, 11, 128, 411, 47, 47, 47, 412, 413, 160, 160, 160, 47, 47, 47, 47, 47, 414, 415, 416, 417, 47, 47, 418, 419, 420, 47, 47, - 421, 422, 66, 47, 47, 47, 47, 47, 47, 47, 400, 423, 424, 128, 145, 425, - 47, 156, 426, 427, 32, 32, 32, 32, 47, 47, 47, 359, 428, 160, 47, 47, - 429, 430, 160, 160, 160, 160, 160, 160, 47, 47, 47, 47, 47, 47, 47, 431, - 47, 47, 47, 47, 145, 432, 433, 434, 219, 219, 219, 219, 219, 219, 219, 66, - 47, 47, 47, 47, 47, 47, 47, 424, 47, 47, 47, 208, 208, 208, 208, 208, - 47, 47, 47, 47, 47, 47, 305, 47, 47, 47, 47, 47, 160, 47, 47, 435, - 47, 47, 47, 436, 437, 438, 439, 47, 9, 9, 9, 9, 9, 9, 11, 11, - 145, 440, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 391, 441, 416, 416, - 442, 443, 27, 27, 27, 27, 444, 416, 47, 445, 208, 208, 208, 208, 208, 208, - 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 446, 447, - 448, 146, 449, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 146, 146, 146, - 9, 451, 11, 452, 453, 11, 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, - 452, 453, 11, 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, 452, 453, 11, - 196, 9, 454, 455, 9, 456, 11, 9, 451, 11, 196, 9, 457, 458, 459, 460, - 11, 461, 9, 462, 463, 464, 465, 11, 466, 9, 467, 11, 468, 160, 160, 160, - 32, 32, 32, 469, 32, 32, 470, 471, 472, 473, 32, 32, 32, 32, 32, 32, - 474, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 32, 32, 32, 32, 32, - 47, 47, 47, 475, 476, 146, 146, 146, 47, 47, 477, 32, 47, 47, 478, 479, - 47, 47, 47, 47, 355, 32, 32, 32, 9, 9, 454, 11, 480, 305, 66, 66, - 145, 145, 481, 482, 145, 145, 145, 145, 145, 145, 483, 145, 145, 145, 145, 145, - 47, 47, 47, 47, 47, 47, 47, 226, 484, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 485, 146, 146, 146, 146, 146, 146, 146, 160, + 421, 422, 66, 47, 47, 47, 47, 47, 66, 66, 66, 66, 66, 66, 66, 66, + 47, 47, 400, 423, 424, 128, 145, 425, 47, 156, 426, 427, 32, 32, 32, 32, + 47, 47, 47, 359, 428, 160, 47, 47, 429, 430, 160, 160, 160, 160, 160, 160, + 47, 47, 47, 47, 47, 47, 47, 431, 432, 47, 47, 433, 434, 160, 160, 160, + 47, 47, 47, 47, 145, 435, 436, 437, 219, 219, 219, 219, 219, 219, 219, 66, + 47, 47, 47, 47, 47, 47, 47, 424, 47, 47, 47, 208, 438, 32, 32, 32, + 47, 47, 47, 47, 47, 47, 305, 47, 47, 47, 47, 47, 160, 47, 47, 439, + 47, 47, 47, 440, 441, 442, 443, 47, 9, 9, 9, 9, 9, 9, 11, 11, + 145, 444, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 391, 445, 416, 416, + 446, 447, 27, 27, 27, 27, 448, 416, 47, 449, 208, 208, 208, 208, 208, 208, + 32, 32, 32, 32, 32, 146, 146, 146, 146, 146, 146, 146, 146, 146, 450, 451, + 452, 146, 453, 146, 146, 146, 146, 146, 146, 146, 146, 146, 454, 146, 146, 146, + 9, 455, 11, 456, 457, 11, 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, + 456, 457, 11, 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, 456, 457, 11, + 196, 9, 458, 459, 9, 460, 11, 9, 455, 11, 196, 9, 461, 462, 463, 464, + 11, 465, 9, 466, 467, 468, 469, 11, 470, 9, 471, 11, 472, 160, 160, 160, + 32, 32, 32, 473, 32, 32, 474, 475, 476, 477, 32, 32, 32, 32, 32, 32, + 478, 11, 11, 11, 11, 11, 11, 11, 32, 32, 32, 27, 27, 27, 27, 27, + 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 47, 479, 480, 146, 146, 146, + 47, 47, 481, 32, 47, 47, 482, 483, 47, 47, 47, 47, 47, 47, 484, 160, + 47, 47, 47, 47, 355, 32, 32, 32, 9, 9, 458, 11, 485, 305, 66, 66, + 145, 145, 486, 487, 145, 145, 145, 145, 145, 145, 488, 145, 145, 145, 145, 145, + 47, 47, 47, 47, 47, 47, 47, 226, 489, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 490, 146, 146, 146, 146, 146, 146, 146, 160, 208, 208, 208, 208, 208, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, @@ -5712,12 +5779,12 @@ _hb_ucd_i16[92] = static inline uint_fast8_t _hb_ucd_gc (unsigned u) { - return u<1114112u?_hb_ucd_u8[5056+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114112u?_hb_ucd_u8[5080+(((_hb_ucd_u8[1152+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; } static inline uint_fast8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[6970+(((_hb_ucd_u8[6426+(((_hb_ucd_u8[5982+(((_hb_ucd_u8[5646+(((_hb_ucd_u8[5400+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; + return u<125259u?_hb_ucd_u8[7038+(((_hb_ucd_u8[6482+(((_hb_ucd_u8[6022+(((_hb_ucd_u8[5670+(((_hb_ucd_u8[5424+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; } static inline unsigned _hb_ucd_b4 (const uint8_t* a, unsigned i) @@ -5727,17 +5794,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i) static inline int_fast16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7858+(((_hb_ucd_u8[7626+(((_hb_ucd_u8[7530+(((_hb_ucd_b4(7466+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7930+(((_hb_ucd_u8[7698+(((_hb_ucd_u8[7602+(((_hb_ucd_b4(7538+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; } static inline uint_fast8_t _hb_ucd_sc (unsigned u) { - return u<918016u?_hb_ucd_u8[11124+(((_hb_ucd_u8[10176+(((_hb_ucd_u8[9204+(((_hb_ucd_u8[8524+(((_hb_ucd_u8[8220+(((_hb_ucd_u8[8106+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2; + return u<918016u?_hb_ucd_u8[11228+(((_hb_ucd_u8[10264+(((_hb_ucd_u8[9276+(((_hb_ucd_u8[8596+(((_hb_ucd_u8[8292+(((_hb_ucd_u8[8178+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2; } static inline uint_fast16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[1576+(((_hb_ucd_u8[12446+(((_hb_ucd_u8[12064+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; + return u<195102u?_hb_ucd_u16[1608+(((_hb_ucd_u8[12570+(((_hb_ucd_u8[12188+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; } #endif diff --git a/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh b/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh index 036c71a424..13b1c4b1d4 100644 --- a/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh +++ b/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh @@ -6,16 +6,16 @@ * * on file with this header: * - * # emoji-data-14.0.0.txt - * # Date: 2021-08-26, 17:22:22 GMT - * # © 2021 Unicode®, Inc. + * # emoji-data.txt + * # Date: 2022-08-02, 00:26:10 GMT + * # © 2022 Unicode®, Inc. * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. - * # For terms of use, see http://www.unicode.org/terms_of_use.html + * # For terms of use, see https://www.unicode.org/terms_of_use.html * # * # Emoji Data for UTS #51 - * # Used with Emoji Version 14.0 and subsequent minor revisions (if any) + * # Used with Emoji Version 15.0 and subsequent minor revisions (if any) * # - * # For documentation and usage, see http://www.unicode.org/reports/tr51 + * # For documentation and usage, see https://www.unicode.org/reports/tr51 */ #ifndef HB_UNICODE_EMOJI_TABLE_HH diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h index a1586a58b6..fa7403cae7 100644 --- a/thirdparty/harfbuzz/src/hb-version.h +++ b/thirdparty/harfbuzz/src/hb-version.h @@ -47,7 +47,7 @@ HB_BEGIN_DECLS * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 1 +#define HB_VERSION_MINOR 2 /** * HB_VERSION_MICRO: * @@ -60,7 +60,7 @@ HB_BEGIN_DECLS * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "5.1.0" +#define HB_VERSION_STRING "5.2.0" /** * HB_VERSION_ATLEAST: diff --git a/thirdparty/libpng/LICENSE b/thirdparty/libpng/LICENSE index e0c5b531cf..c8ad24eecf 100644 --- a/thirdparty/libpng/LICENSE +++ b/thirdparty/libpng/LICENSE @@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE PNG Reference Library License version 2 --------------------------------------- - * Copyright (c) 1995-2019 The PNG Reference Library Authors. - * Copyright (c) 2018-2019 Cosmin Truta. + * Copyright (c) 1995-2022 The PNG Reference Library Authors. + * Copyright (c) 2018-2022 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. diff --git a/thirdparty/libpng/arm/arm_init.c b/thirdparty/libpng/arm/arm_init.c index a34ecdbef7..ab22525b38 100644 --- a/thirdparty/libpng/arm/arm_init.c +++ b/thirdparty/libpng/arm/arm_init.c @@ -1,7 +1,7 @@ /* arm_init.c - NEON optimised filter functions * - * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 2014,2016 Glenn Randers-Pehrson * Written by Mans Rullgard, 2011. * @@ -10,9 +10,7 @@ * and license in png.h */ -/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are - * called. - */ +/* This module requires POSIX 1003.1 functions. */ #define _POSIX_SOURCE 1 #include "../pngpriv.h" @@ -33,21 +31,23 @@ * has partial support is contrib/arm-neon/linux.c - a generic Linux * implementation which reads /proc/cpufino. */ +#include <signal.h> /* for sig_atomic_t */ + #ifndef PNG_ARM_NEON_FILE -# ifdef __linux__ -# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c" +# if defined(__aarch64__) || defined(_M_ARM64) + /* ARM Neon is expected to be unconditionally available on ARM64. */ +# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this platform" +# elif defined(__linux__) +# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c" +# else +# error "No support for run-time ARM Neon checking; use compile-time options" # endif #endif -#ifdef PNG_ARM_NEON_FILE - -#include <signal.h> /* for sig_atomic_t */ static int png_have_neon(png_structp png_ptr); -#include PNG_ARM_NEON_FILE - -#else /* PNG_ARM_NEON_FILE */ -# error "PNG_ARM_NEON_FILE undefined: no support for run-time ARM NEON checks" -#endif /* PNG_ARM_NEON_FILE */ +#ifdef PNG_ARM_NEON_FILE +# include PNG_ARM_NEON_FILE +#endif #endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ #ifndef PNG_ALIGNED_MEMORY_SUPPORTED diff --git a/thirdparty/libpng/arm/filter_neon_intrinsics.c b/thirdparty/libpng/arm/filter_neon_intrinsics.c index 553c0be21c..4466d48b20 100644 --- a/thirdparty/libpng/arm/filter_neon_intrinsics.c +++ b/thirdparty/libpng/arm/filter_neon_intrinsics.c @@ -18,7 +18,7 @@ /* This code requires -mfpu=neon on the command line: */ #if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */ -#if defined(_MSC_VER) && defined(_M_ARM64) +#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) # include <arm64_neon.h> #else # include <arm_neon.h> diff --git a/thirdparty/libpng/arm/palette_neon_intrinsics.c b/thirdparty/libpng/arm/palette_neon_intrinsics.c index b4d1fd2abf..92c7d6f9f6 100644 --- a/thirdparty/libpng/arm/palette_neon_intrinsics.c +++ b/thirdparty/libpng/arm/palette_neon_intrinsics.c @@ -14,7 +14,7 @@ #if PNG_ARM_NEON_IMPLEMENTATION == 1 -#if defined(_MSC_VER) && defined(_M_ARM64) +#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) # include <arm64_neon.h> #else # include <arm_neon.h> @@ -30,8 +30,6 @@ png_riffle_palette_neon(png_structrp png_ptr) int num_trans = png_ptr->num_trans; int i; - png_debug(1, "in png_riffle_palette_neon"); - /* Initially black, opaque. */ uint8x16x4_t w = {{ vdupq_n_u8(0x00), @@ -40,6 +38,8 @@ png_riffle_palette_neon(png_structrp png_ptr) vdupq_n_u8(0xff), }}; + png_debug(1, "in png_riffle_palette_neon"); + /* First, riffle the RGB colours into an RGBA8 palette. * The alpha component is set to opaque for now. */ @@ -65,11 +65,12 @@ png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info, png_uint_32 row_width = row_info->width; const png_uint_32 *riffled_palette = (const png_uint_32 *)png_ptr->riffled_palette; - const png_int_32 pixels_per_chunk = 4; - int i; + const png_uint_32 pixels_per_chunk = 4; + png_uint_32 i; png_debug(1, "in png_do_expand_palette_rgba8_neon"); + PNG_UNUSED(row) if (row_width < pixels_per_chunk) return 0; @@ -109,10 +110,11 @@ png_do_expand_palette_rgb8_neon(png_structrp png_ptr, png_row_infop row_info, png_uint_32 row_width = row_info->width; png_const_bytep palette = (png_const_bytep)png_ptr->palette; const png_uint_32 pixels_per_chunk = 8; - int i; + png_uint_32 i; png_debug(1, "in png_do_expand_palette_rgb8_neon"); + PNG_UNUSED(row) if (row_width <= pixels_per_chunk) return 0; diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c index 757c755f97..fc09564262 100644 --- a/thirdparty/libpng/png.c +++ b/thirdparty/libpng/png.c @@ -1,7 +1,7 @@ /* png.c - location for general purpose libpng functions * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -14,7 +14,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_37 Your_png_h_is_not_version_1_6_37; +typedef png_libpng_version_1_6_38 Your_png_h_is_not_version_1_6_38; #ifdef __GNUC__ /* The version tests may need to be added to, but the problem warning has @@ -720,7 +720,7 @@ png_init_io(png_structrp png_ptr, png_FILE_p fp) * * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the * negative integral value is added the result will be an unsigned value - * correspnding to the 2's complement representation. + * corresponding to the 2's complement representation. */ void PNGAPI png_save_int_32(png_bytep buf, png_int_32 i) @@ -815,8 +815,8 @@ png_get_copyright(png_const_structrp png_ptr) return PNG_STRING_COPYRIGHT #else return PNG_STRING_NEWLINE \ - "libpng version 1.6.37" PNG_STRING_NEWLINE \ - "Copyright (c) 2018-2019 Cosmin Truta" PNG_STRING_NEWLINE \ + "libpng version 1.6.38" PNG_STRING_NEWLINE \ + "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ @@ -1843,12 +1843,12 @@ png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, # ifdef PNG_WARNINGS_SUPPORTED else { - char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */ pos = png_safecat(message, (sizeof message), pos, png_format_number(number, number+(sizeof number), PNG_NUMBER_FORMAT_x, value)); - pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ + pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */ } # endif /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h index b12174ba35..5fb494fb1a 100644 --- a/thirdparty/libpng/png.h +++ b/thirdparty/libpng/png.h @@ -1,9 +1,9 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.37 - April 14, 2019 + * libpng version 1.6.38 - September 14, 2022 * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -15,7 +15,7 @@ * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.35, July 2018: * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.37, April 2019: + * libpng versions 1.6.36, December 2018, through 1.6.38, September 2022: * Cosmin Truta * See also "Contributing Authors", below. */ @@ -27,8 +27,8 @@ * PNG Reference Library License version 2 * --------------------------------------- * - * * Copyright (c) 1995-2019 The PNG Reference Library Authors. - * * Copyright (c) 2018-2019 Cosmin Truta. + * * Copyright (c) 1995-2022 The PNG Reference Library Authors. + * * Copyright (c) 2018-2022 Cosmin Truta. * * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * * Copyright (c) 1996-1997 Andreas Dilger. * * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -239,7 +239,7 @@ * ... * 1.5.30 15 10530 15.so.15.30[.0] * ... - * 1.6.37 16 10637 16.so.16.37[.0] + * 1.6.38 16 10638 16.so.16.38[.0] * * Henceforth the source version will match the shared-library major and * minor numbers; the shared-library major version number will be used for @@ -278,8 +278,8 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.37" -#define PNG_HEADER_VERSION_STRING " libpng version 1.6.37 - April 14, 2019\n" +#define PNG_LIBPNG_VER_STRING "1.6.38" +#define PNG_HEADER_VERSION_STRING " libpng version 1.6.38 - September 14, 2022\n" #define PNG_LIBPNG_VER_SONUM 16 #define PNG_LIBPNG_VER_DLLNUM 16 @@ -287,7 +287,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 37 +#define PNG_LIBPNG_VER_RELEASE 38 /* This should be zero for a public release, or non-zero for a * development version. [Deprecated] @@ -318,7 +318,7 @@ * From version 1.0.1 it is: * XXYYZZ, where XX=major, YY=minor, ZZ=release */ -#define PNG_LIBPNG_VER 10637 /* 1.6.37 */ +#define PNG_LIBPNG_VER 10638 /* 1.6.38 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -330,10 +330,6 @@ # include "pnglibconf.h" #endif -#define PNG_APNG_SUPPORTED -#define PNG_READ_APNG_SUPPORTED -#define PNG_WRITE_APNG_SUPPORTED - #ifndef PNG_VERSION_INFO_ONLY /* Machine specific configuration. */ # include "pngconf.h" @@ -429,21 +425,10 @@ extern "C" { * See pngconf.h for base types that vary by machine/system */ -#ifdef PNG_APNG_SUPPORTED -/* dispose_op flags from inside fcTL */ -#define PNG_DISPOSE_OP_NONE 0x00U -#define PNG_DISPOSE_OP_BACKGROUND 0x01U -#define PNG_DISPOSE_OP_PREVIOUS 0x02U - -/* blend_op flags from inside fcTL */ -#define PNG_BLEND_OP_SOURCE 0x00U -#define PNG_BLEND_OP_OVER 0x01U -#endif /* PNG_APNG_SUPPORTED */ - /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_6_37; +typedef char* png_libpng_version_1_6_38; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -761,10 +746,6 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ -#ifdef PNG_APNG_SUPPORTED -#define PNG_INFO_acTL 0x20000U -#define PNG_INFO_fcTL 0x40000U -#endif /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using @@ -802,10 +783,6 @@ typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, #ifdef PNG_PROGRESSIVE_READ_SUPPORTED typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); -#ifdef PNG_APNG_SUPPORTED -typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp, - png_uint_32)); -#endif /* The following callback receives png_uint_32 row_number, int pass for the * png_bytep data of the row. When transforming an interlaced image the @@ -1469,7 +1446,7 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, * mainly useful for testing, as the defaults should work with most users. * Those users who are tight on memory or want faster performance at the * expense of compression can modify them. See the compression library - * header file (zlib.h) for an explination of the compression functions. + * header file (zlib.h) for an explanation of the compression functions. */ /* Set the filtering method(s) used by libpng. Currently, the only valid @@ -1524,7 +1501,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 * (0 - no compression, 9 - "maximal" compression). Note that tests have * shown that zlib compression levels 3-6 usually perform as well as level 9 - * for PNG images, and do considerably fewer caclulations. In the future, + * for PNG images, and do considerably fewer calculations. In the future, * these values may not correspond directly to the zlib compression levels. */ #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED @@ -3249,74 +3226,6 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, /******************************************************************************* * END OF HARDWARE AND SOFTWARE OPTIONS ******************************************************************************/ -#ifdef PNG_APNG_SUPPORTED -PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr, - png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays)); - -PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr, - png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays)); - -PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr, - png_infop info_ptr)); - -PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr, - png_infop info_ptr)); - -PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL, - (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width, - png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset, - png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op, - png_byte *blend_op)); - -PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL, - (png_structp png_ptr, png_infop info_ptr, png_uint_32 width, - png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, - png_byte blend_op)); - -PNG_EXPORT(256, png_uint_32, png_get_next_frame_width, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(257, png_uint_32, png_get_next_frame_height, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden, - (png_structp png_ptr, png_infop info_ptr)); -PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden, - (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden)); - -#ifdef PNG_READ_APNG_SUPPORTED -PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr, - png_infop info_ptr)); -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr, - png_progressive_frame_ptr frame_info_fn, - png_progressive_frame_ptr frame_end_fn)); -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ -#endif /* PNG_READ_APNG_SUPPORTED */ - -#ifdef PNG_WRITE_APNG_SUPPORTED -PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr, - png_infop info_ptr, png_bytepp row_pointers, - png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, - png_byte blend_op)); - -PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr, - png_infop info_ptr)); -#endif /* PNG_WRITE_APNG_SUPPORTED */ -#endif /* PNG_APNG_SUPPORTED */ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project * defs, and in scripts/symbols.def. @@ -3326,11 +3235,7 @@ PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr, * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL -#ifdef PNG_APNG_SUPPORTED - PNG_EXPORT_LAST_ORDINAL(269); -#else PNG_EXPORT_LAST_ORDINAL(249); -#endif /* PNG_APNG_SUPPORTED */ #endif #ifdef __cplusplus diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h index 927a769dbe..89d28f83a0 100644 --- a/thirdparty/libpng/pngconf.h +++ b/thirdparty/libpng/pngconf.h @@ -1,9 +1,9 @@ /* pngconf.h - machine-configurable file for libpng * - * libpng version 1.6.37 + * libpng version 1.6.38 * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -180,8 +180,8 @@ * compiler-specific macros to the values required to change the calling * conventions of the various functions. */ -#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ - defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \ + defined(__CYGWIN__) /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or * MinGW on any architecture currently supported by Windows. Also includes * Watcom builds but these need special treatment because they are not diff --git a/thirdparty/libpng/pngget.c b/thirdparty/libpng/pngget.c index 9ed101aedc..e44933c0d2 100644 --- a/thirdparty/libpng/pngget.c +++ b/thirdparty/libpng/pngget.c @@ -1151,7 +1151,7 @@ png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte PNGAPI -png_get_rgb_to_gray_status (png_const_structrp png_ptr) +png_get_rgb_to_gray_status(png_const_structrp png_ptr) { return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); } @@ -1192,27 +1192,27 @@ png_get_compression_buffer_size(png_const_structrp png_ptr) /* These functions were added to libpng 1.2.6 and were enabled * by default in libpng-1.4.0 */ png_uint_32 PNGAPI -png_get_user_width_max (png_const_structrp png_ptr) +png_get_user_width_max(png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_width_max : 0); } png_uint_32 PNGAPI -png_get_user_height_max (png_const_structrp png_ptr) +png_get_user_height_max(png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_height_max : 0); } /* This function was added to libpng 1.4.0 */ png_uint_32 PNGAPI -png_get_chunk_cache_max (png_const_structrp png_ptr) +png_get_chunk_cache_max(png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_cache_max : 0); } /* This function was added to libpng 1.4.1 */ png_alloc_size_t PNGAPI -png_get_chunk_malloc_max (png_const_structrp png_ptr) +png_get_chunk_malloc_max(png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); } @@ -1221,13 +1221,13 @@ png_get_chunk_malloc_max (png_const_structrp png_ptr) /* These functions were added to libpng 1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED png_uint_32 PNGAPI -png_get_io_state (png_const_structrp png_ptr) +png_get_io_state(png_const_structrp png_ptr) { return png_ptr->io_state; } png_uint_32 PNGAPI -png_get_io_chunk_type (png_const_structrp png_ptr) +png_get_io_chunk_type(png_const_structrp png_ptr) { return png_ptr->chunk_name; } @@ -1246,166 +1246,4 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) # endif #endif -#ifdef PNG_APNG_SUPPORTED -png_uint_32 PNGAPI -png_get_acTL(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *num_frames, png_uint_32 *num_plays) -{ - png_debug1(1, "in %s retrieval function", "acTL"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_acTL) && - num_frames != NULL && num_plays != NULL) - { - *num_frames = info_ptr->num_frames; - *num_plays = info_ptr->num_plays; - return (1); - } - - return (0); -} - -png_uint_32 PNGAPI -png_get_num_frames(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_num_frames()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->num_frames); - return (0); -} - -png_uint_32 PNGAPI -png_get_num_plays(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_num_plays()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->num_plays); - return (0); -} - -png_uint_32 PNGAPI -png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *width, png_uint_32 *height, - png_uint_32 *x_offset, png_uint_32 *y_offset, - png_uint_16 *delay_num, png_uint_16 *delay_den, - png_byte *dispose_op, png_byte *blend_op) -{ - png_debug1(1, "in %s retrieval function", "fcTL"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_fcTL) && - width != NULL && height != NULL && - x_offset != NULL && y_offset != NULL && - delay_num != NULL && delay_den != NULL && - dispose_op != NULL && blend_op != NULL) - { - *width = info_ptr->next_frame_width; - *height = info_ptr->next_frame_height; - *x_offset = info_ptr->next_frame_x_offset; - *y_offset = info_ptr->next_frame_y_offset; - *delay_num = info_ptr->next_frame_delay_num; - *delay_den = info_ptr->next_frame_delay_den; - *dispose_op = info_ptr->next_frame_dispose_op; - *blend_op = info_ptr->next_frame_blend_op; - return (1); - } - - return (0); -} - -png_uint_32 PNGAPI -png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_width()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_width); - return (0); -} - -png_uint_32 PNGAPI -png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_height()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_height); - return (0); -} - -png_uint_32 PNGAPI -png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_x_offset()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_x_offset); - return (0); -} - -png_uint_32 PNGAPI -png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_y_offset()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_y_offset); - return (0); -} - -png_uint_16 PNGAPI -png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_delay_num()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_delay_num); - return (0); -} - -png_uint_16 PNGAPI -png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_delay_den()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_delay_den); - return (0); -} - -png_byte PNGAPI -png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_dispose_op()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_dispose_op); - return (0); -} - -png_byte PNGAPI -png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_get_next_frame_blend_op()"); - - if (png_ptr != NULL && info_ptr != NULL) - return (info_ptr->next_frame_blend_op); - return (0); -} - -png_byte PNGAPI -png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_first_frame_is_hidden()"); - - if (png_ptr != NULL) - return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN); - - PNG_UNUSED(info_ptr) - - return 0; -} -#endif /* PNG_APNG_SUPPORTED */ #endif /* READ || WRITE */ diff --git a/thirdparty/libpng/pnginfo.h b/thirdparty/libpng/pnginfo.h index ac7b269132..1f98dedc42 100644 --- a/thirdparty/libpng/pnginfo.h +++ b/thirdparty/libpng/pnginfo.h @@ -263,18 +263,5 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) png_bytepp row_pointers; /* the image bits */ #endif -#ifdef PNG_APNG_SUPPORTED - png_uint_32 num_frames; /* including default image */ - png_uint_32 num_plays; - png_uint_32 next_frame_width; - png_uint_32 next_frame_height; - png_uint_32 next_frame_x_offset; - png_uint_32 next_frame_y_offset; - png_uint_16 next_frame_delay_num; - png_uint_16 next_frame_delay_den; - png_byte next_frame_dispose_op; - png_byte next_frame_blend_op; -#endif - }; #endif /* PNGINFO_H */ diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h index e1e27e957e..89d5b4c8ad 100644 --- a/thirdparty/libpng/pnglibconf.h +++ b/thirdparty/libpng/pnglibconf.h @@ -1,8 +1,8 @@ /* pnglibconf.h - library build configuration */ -/* libpng version 1.6.37 */ +/* libpng version 1.6.38 */ -/* Copyright (c) 2018-2019 Cosmin Truta */ +/* Copyright (c) 2018-2022 Cosmin Truta */ /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ /* This code is released under the libpng license. */ diff --git a/thirdparty/libpng/pngpread.c b/thirdparty/libpng/pngpread.c index 2eaeca08f7..e283627b77 100644 --- a/thirdparty/libpng/pngpread.c +++ b/thirdparty/libpng/pngpread.c @@ -195,106 +195,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) chunk_name = png_ptr->chunk_name; -#ifdef PNG_READ_APNG_SUPPORTED - if (png_ptr->num_frames_read > 0 && - png_ptr->num_frames_read < info_ptr->num_frames) - { - if (chunk_name == png_IDAT) - { - /* Discard trailing IDATs for the first frame */ - if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1) - png_error(png_ptr, "out of place IDAT"); - - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - return; - } - else if (chunk_name == png_fdAT) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_ensure_sequence_number(png_ptr, 4); - - if (!(png_ptr->mode & PNG_HAVE_fcTL)) - { - /* Discard trailing fdATs for frames other than the first */ - if (png_ptr->num_frames_read < 2) - png_error(png_ptr, "out of place fdAT"); - - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - return; - } - - else - { - /* frame data follows */ - png_ptr->idat_size = png_ptr->push_length - 4; - png_ptr->mode |= PNG_HAVE_IDAT; - png_ptr->process_mode = PNG_READ_IDAT_MODE; - - return; - } - } - - else if (chunk_name == png_fcTL) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_read_reset(png_ptr); - png_ptr->mode &= ~PNG_HAVE_fcTL; - - png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length); - - if (!(png_ptr->mode & PNG_HAVE_fcTL)) - png_error(png_ptr, "missing required fcTL chunk"); - - png_read_reinit(png_ptr, info_ptr); - png_progressive_read_reset(png_ptr); - - if (png_ptr->frame_info_fn != NULL) - (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read); - - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - - return; - } - - else - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_warning(png_ptr, "Skipped (ignored) a chunk " - "between APNG chunks"); - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - return; - } - - return; - } -#endif /* PNG_READ_APNG_SUPPORTED */ - if (chunk_name == png_IDAT) { if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) @@ -361,9 +261,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) else if (chunk_name == png_IDAT) { -#ifdef PNG_READ_APNG_SUPPORTED - png_have_info(png_ptr, info_ptr); -#endif png_ptr->idat_size = png_ptr->push_length; png_ptr->process_mode = PNG_READ_IDAT_MODE; png_push_have_info(png_ptr, info_ptr); @@ -509,30 +406,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif -#ifdef PNG_READ_APNG_SUPPORTED - else if (chunk_name == png_acTL) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (chunk_name == png_fcTL) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif /* PNG_READ_APNG_SUPPORTED */ else { @@ -666,11 +539,7 @@ png_push_read_IDAT(png_structrp png_ptr) png_byte chunk_tag[4]; /* TODO: this code can be commoned up with the same code in push_read */ -#ifdef PNG_READ_APNG_SUPPORTED - PNG_PUSH_SAVE_BUFFER_IF_LT(12) -#else PNG_PUSH_SAVE_BUFFER_IF_LT(8) -#endif png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); @@ -678,64 +547,17 @@ png_push_read_IDAT(png_structrp png_ptr) png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; -#ifdef PNG_READ_APNG_SUPPORTED - if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0) - { - if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - if (png_ptr->frame_end_fn != NULL) - (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read); - png_ptr->num_frames_read++; - return; - } - else - { - if (png_ptr->chunk_name == png_IEND) - png_error(png_ptr, "Not enough image data"); - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_warning(png_ptr, "Skipping (ignoring) a chunk between " - "APNG chunks"); - png_crc_finish(png_ptr, png_ptr->push_length); - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - return; - } - } - else -#endif -#ifdef PNG_READ_APNG_SUPPORTED - if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0) -#else if (png_ptr->chunk_name != png_IDAT) -#endif { png_ptr->process_mode = PNG_READ_CHUNK_MODE; if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) png_error(png_ptr, "Not enough compressed data"); -#ifdef PNG_READ_APNG_SUPPORTED - if (png_ptr->frame_end_fn != NULL) - (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read); - png_ptr->num_frames_read++; -#endif - return; } png_ptr->idat_size = png_ptr->push_length; - -#ifdef PNG_READ_APNG_SUPPORTED - if (png_ptr->num_frames_read > 0) - { - png_ensure_sequence_number(png_ptr, 4); - png_ptr->idat_size -= 4; - } -#endif } if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) @@ -809,15 +631,6 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, if (!(buffer_length > 0) || buffer == NULL) png_error(png_ptr, "No IDAT data (internal error)"); -#ifdef PNG_READ_APNG_SUPPORTED - /* If the app is not APNG-aware, decode only the first frame */ - if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0) - { - png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; - return; - } -#endif - /* This routine must process all the data it has been given * before returning, calling the row callback as required to * handle the uncompressed results. @@ -1272,18 +1085,6 @@ png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); } -#ifdef PNG_READ_APNG_SUPPORTED -void PNGAPI -png_set_progressive_frame_fn(png_structp png_ptr, - png_progressive_frame_ptr frame_info_fn, - png_progressive_frame_ptr frame_end_fn) -{ - png_ptr->frame_info_fn = frame_info_fn; - png_ptr->frame_end_fn = frame_end_fn; - png_ptr->apng_flags |= PNG_APNG_APP; -} -#endif - png_voidp PNGAPI png_get_progressive_ptr(png_const_structrp png_ptr) { diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h index 57e1bf989b..2e426cf47d 100644 --- a/thirdparty/libpng/pngpriv.h +++ b/thirdparty/libpng/pngpriv.h @@ -1,7 +1,7 @@ /* pngpriv.h - private declarations for use inside libpng * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -174,7 +174,7 @@ # else /* !defined __ARM_NEON__ */ /* The 'intrinsics' code simply won't compile without this -mfpu=neon: */ -# if !defined(__aarch64__) +# if !defined(__aarch64__) && !defined(_M_ARM64) /* The assembler code currently does not work on ARM64 */ # define PNG_ARM_NEON_IMPLEMENTATION 2 # endif /* __aarch64__ */ @@ -185,6 +185,8 @@ /* Use the intrinsics code by default. */ # define PNG_ARM_NEON_IMPLEMENTATION 1 # endif +#else /* PNG_ARM_NEON_OPT == 0 */ +# define PNG_ARM_NEON_IMPLEMENTATION 0 #endif /* PNG_ARM_NEON_OPT > 0 */ #ifndef PNG_MIPS_MSA_OPT @@ -263,11 +265,15 @@ # ifndef PNG_MIPS_MSA_IMPLEMENTATION # define PNG_MIPS_MSA_IMPLEMENTATION 1 # endif +#else +# define PNG_MIPS_MSA_IMPLEMENTATION 0 #endif /* PNG_MIPS_MSA_OPT > 0 */ #if PNG_POWERPC_VSX_OPT > 0 # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx # define PNG_POWERPC_VSX_IMPLEMENTATION 1 +#else +# define PNG_POWERPC_VSX_IMPLEMENTATION 0 #endif @@ -492,16 +498,7 @@ static_cast<type>(static_cast<const void*>(value)) #else # define png_voidcast(type, value) (value) -# ifdef _WIN64 -# ifdef __GNUC__ - typedef unsigned long long png_ptruint; -# else - typedef unsigned __int64 png_ptruint; -# endif -# else - typedef unsigned long png_ptruint; -# endif -# define png_constcast(type, value) ((type)(png_ptruint)(const void*)(value)) +# define png_constcast(type, value) ((type)(void*)(const void*)(value)) # define png_aligncast(type, value) ((void*)(value)) # define png_aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ @@ -543,9 +540,8 @@ # include <alloc.h> #endif -#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ - defined(_WIN32) || defined(__WIN32__) -# include <windows.h> /* defines _WINDOWS_ macro */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# include <windows.h> #endif #endif /* PNG_VERSION_INFO_ONLY */ @@ -554,24 +550,20 @@ * functions that are passed far data must be model-independent. */ -/* Memory model/platform independent fns */ +/* Platform-independent functions */ #ifndef PNG_ABORT -# ifdef _WINDOWS_ -# define PNG_ABORT() ExitProcess(0) -# else -# define PNG_ABORT() abort() -# endif +# define PNG_ABORT() abort() #endif /* These macros may need to be architecture dependent. */ -#define PNG_ALIGN_NONE 0 /* do not use data alignment */ -#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ #ifdef offsetof -# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ #else # define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ #endif -#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ #ifndef PNG_ALIGN_TYPE /* Default to using aligned access optimizations and requiring alignment to a @@ -585,26 +577,25 @@ /* This is used because in some compiler implementations non-aligned * structure members are supported, so the offsetof approach below fails. * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access - * is good for performance. Do not do this unless you have tested the result - * and understand it. + * is good for performance. Do not do this unless you have tested the + * result and understand it. */ -# define png_alignof(type) (sizeof (type)) +# define png_alignof(type) (sizeof(type)) #else # if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET -# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# define png_alignof(type) offsetof(struct{char c; type t;}, t) # else -# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS -# define png_alignof(type) (1) -# endif - /* Else leave png_alignof undefined to prevent use thereof */ +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) 1 +# endif + /* Else leave png_alignof undefined to prevent use thereof */ # endif #endif -/* This implicitly assumes alignment is always to a power of 2. */ +/* This implicitly assumes alignment is always a multiple of 2. */ #ifdef png_alignof -# define png_isaligned(ptr, type)\ - (((type)((const char*)ptr-(const char*)0) & \ - (type)(png_alignof(type)-1)) == 0) +# define png_isaligned(ptr, type) \ + (((type)(size_t)((const void*)(ptr)) & (type)(png_alignof(type)-1)) == 0) #else # define png_isaligned(ptr, type) 0 #endif @@ -637,10 +628,6 @@ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */ /* 0x4000U (unused) */ #define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */ -#ifdef PNG_APNG_SUPPORTED -#define PNG_HAVE_acTL 0x10000U -#define PNG_HAVE_fcTL 0x20000U -#endif /* Flags for the transformations the PNG library does on the image data */ #define PNG_BGR 0x0001U @@ -877,16 +864,6 @@ #define png_tRNS PNG_U32(116, 82, 78, 83) #define png_zTXt PNG_U32(122, 84, 88, 116) -#ifdef PNG_APNG_SUPPORTED -#define png_acTL PNG_U32( 97, 99, 84, 76) -#define png_fcTL PNG_U32(102, 99, 84, 76) -#define png_fdAT PNG_U32(102, 100, 65, 84) - -/* For png_struct.apng_flags: */ -#define PNG_FIRST_FRAME_HIDDEN 0x0001U -#define PNG_APNG_APP 0x0002U -#endif - /* The following will work on (signed char*) strings, whereas the get_uint_32 * macro will fail on top-bit-set values because of the sign extension. */ @@ -1658,47 +1635,6 @@ PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, */ #endif -#ifdef PNG_APNG_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr, - png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, - png_byte dispose_op, png_byte blend_op), PNG_EMPTY); - -#ifdef PNG_READ_APNG_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr, - png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr, - png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr, - png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr, - png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr, - png_infop info_ptr),PNG_EMPTY); -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY); -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ -#endif /* PNG_READ_APNG_SUPPORTED */ - -#ifdef PNG_WRITE_APNG_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr, - png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr, - png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, - png_byte dispose_op, png_byte blend_op),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr, - png_const_bytep data, png_size_t length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr, - png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY); -#endif /* PNG_WRITE_APNG_SUPPORTED */ -#endif /* PNG_APNG_SUPPORTED */ - /* Added at libpng version 1.4.0 */ #ifdef PNG_COLORSPACE_SUPPORTED /* These internal functions are for maintaining the colorspace structure within diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c index fa44d5a8e4..5ab9224038 100644 --- a/thirdparty/libpng/pngread.c +++ b/thirdparty/libpng/pngread.c @@ -161,9 +161,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) else if (chunk_name == png_IDAT) { -#ifdef PNG_READ_APNG_SUPPORTED - png_have_info(png_ptr, info_ptr); -#endif png_ptr->idat_size = length; break; } @@ -258,17 +255,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) png_handle_iTXt(png_ptr, info_ptr, length); #endif -#ifdef PNG_READ_APNG_SUPPORTED - else if (chunk_name == png_acTL) - png_handle_acTL(png_ptr, info_ptr, length); - - else if (chunk_name == png_fcTL) - png_handle_fcTL(png_ptr, info_ptr, length); - - else if (chunk_name == png_fdAT) - png_handle_fdAT(png_ptr, info_ptr, length); -#endif - else png_handle_unknown(png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT); @@ -276,72 +262,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) } #endif /* SEQUENTIAL_READ */ -#ifdef PNG_READ_APNG_SUPPORTED -void PNGAPI -png_read_frame_head(png_structp png_ptr, png_infop info_ptr) -{ - png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */ - - png_debug(0, "Reading frame head"); - - if (!(png_ptr->mode & PNG_HAVE_acTL)) - png_error(png_ptr, "attempt to png_read_frame_head() but " - "no acTL present"); - - /* do nothing for the main IDAT */ - if (png_ptr->num_frames_read == 0) - return; - - png_read_reset(png_ptr); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; - png_ptr->mode &= ~PNG_HAVE_fcTL; - - have_chunk_after_DAT = 0; - for (;;) - { - png_uint_32 length = png_read_chunk_header(png_ptr); - - if (png_ptr->chunk_name == png_IDAT) - { - /* discard trailing IDATs for the first frame */ - if (have_chunk_after_DAT || png_ptr->num_frames_read > 1) - png_error(png_ptr, "png_read_frame_head(): out of place IDAT"); - png_crc_finish(png_ptr, length); - } - - else if (png_ptr->chunk_name == png_fcTL) - { - png_handle_fcTL(png_ptr, info_ptr, length); - have_chunk_after_DAT = 1; - } - - else if (png_ptr->chunk_name == png_fdAT) - { - png_ensure_sequence_number(png_ptr, length); - - /* discard trailing fdATs for frames other than the first */ - if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1) - png_crc_finish(png_ptr, length - 4); - else if(png_ptr->mode & PNG_HAVE_fcTL) - { - png_ptr->idat_size = length - 4; - png_ptr->mode |= PNG_HAVE_IDAT; - - break; - } - else - png_error(png_ptr, "png_read_frame_head(): out of place fdAT"); - } - else - { - png_warning(png_ptr, "Skipped (ignored) a chunk " - "between APNG chunks"); - png_crc_finish(png_ptr, length); - } - } -} -#endif /* PNG_READ_APNG_SUPPORTED */ - /* Optional call to update the users info_ptr structure */ void PNGAPI png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) @@ -3532,7 +3452,6 @@ png_image_read_background(png_voidp argument) for (pass = 0; pass < passes; ++pass) { - png_bytep row = png_voidcast(png_bytep, display->first_row); unsigned int startx, stepx, stepy; png_uint_32 y; @@ -3637,8 +3556,6 @@ png_image_read_background(png_voidp argument) inrow += 2; /* gray and alpha channel */ } - - row += display->row_bytes; } } } diff --git a/thirdparty/libpng/pngrtran.c b/thirdparty/libpng/pngrtran.c index 9a8fad9f4a..238f5afe7e 100644 --- a/thirdparty/libpng/pngrtran.c +++ b/thirdparty/libpng/pngrtran.c @@ -21,7 +21,7 @@ #ifdef PNG_ARM_NEON_IMPLEMENTATION # if PNG_ARM_NEON_IMPLEMENTATION == 1 # define PNG_ARM_NEON_INTRINSICS_AVAILABLE -# if defined(_MSC_VER) && defined(_M_ARM64) +# if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) # include <arm64_neon.h> # else # include <arm_neon.h> diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c index ae66a48a83..ca060dd15f 100644 --- a/thirdparty/libpng/pngrutil.c +++ b/thirdparty/libpng/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -302,7 +302,6 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) if (buffer != NULL && new_size > png_ptr->read_buffer_size) { png_ptr->read_buffer = NULL; - png_ptr->read_buffer = NULL; png_ptr->read_buffer_size = 0; png_free(png_ptr, buffer); buffer = NULL; @@ -865,11 +864,6 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) filter_type = buf[11]; interlace_type = buf[12]; -#ifdef PNG_READ_APNG_SUPPORTED - png_ptr->first_frame_width = width; - png_ptr->first_frame_height = height; -#endif - /* Set internal variables */ png_ptr->width = width; png_ptr->height = height; @@ -2081,21 +2075,22 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_byte buf[1]; png_crc_read(png_ptr, buf, 1); info_ptr->eXIf_buf[i] = buf[0]; - if (i == 1 && buf[0] != 'M' && buf[0] != 'I' - && info_ptr->eXIf_buf[0] != buf[0]) + if (i == 1) { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "incorrect byte-order specifier"); - png_free(png_ptr, info_ptr->eXIf_buf); - info_ptr->eXIf_buf = NULL; - return; + if ((buf[0] != 'M' && buf[0] != 'I') || + (info_ptr->eXIf_buf[0] != buf[0])) + { + png_crc_finish(png_ptr, length - 2); + png_chunk_benign_error(png_ptr, "incorrect byte-order specifier"); + png_free(png_ptr, info_ptr->eXIf_buf); + info_ptr->eXIf_buf = NULL; + return; + } } } - if (png_crc_finish(png_ptr, 0) != 0) - return; - - png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf); + if (png_crc_finish(png_ptr, 0) == 0) + png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf); png_free(png_ptr, info_ptr->eXIf_buf); info_ptr->eXIf_buf = NULL; @@ -2131,8 +2126,9 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) num = length / 2 ; - if (num != (unsigned int) png_ptr->num_palette || - num > (unsigned int) PNG_MAX_PALETTE_LENGTH) + if (length != num * 2 || + num != (unsigned int)png_ptr->num_palette || + num > (unsigned int)PNG_MAX_PALETTE_LENGTH) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); @@ -2862,179 +2858,6 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif -#ifdef PNG_READ_APNG_SUPPORTED -void /* PRIVATE */ -png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte data[8]; - png_uint_32 num_frames; - png_uint_32 num_plays; - png_uint_32 didSet; - - png_debug(1, "in png_handle_acTL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - { - png_error(png_ptr, "Missing IHDR before acTL"); - } - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid acTL after IDAT skipped"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_acTL) - { - png_warning(png_ptr, "Duplicate acTL skipped"); - png_crc_finish(png_ptr, length); - return; - } - else if (length != 8) - { - png_warning(png_ptr, "acTL with invalid length skipped"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, data, 8); - png_crc_finish(png_ptr, 0); - - num_frames = png_get_uint_31(png_ptr, data); - num_plays = png_get_uint_31(png_ptr, data + 4); - - /* the set function will do error checking on num_frames */ - didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays); - if(didSet) - png_ptr->mode |= PNG_HAVE_acTL; -} - -void /* PRIVATE */ -png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte data[22]; - png_uint_32 width; - png_uint_32 height; - png_uint_32 x_offset; - png_uint_32 y_offset; - png_uint_16 delay_num; - png_uint_16 delay_den; - png_byte dispose_op; - png_byte blend_op; - - png_debug(1, "in png_handle_fcTL"); - - png_ensure_sequence_number(png_ptr, length); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - { - png_error(png_ptr, "Missing IHDR before fcTL"); - } - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - /* for any frames other then the first this message may be misleading, - * but correct. PNG_HAVE_IDAT is unset before the frame head is read - * i can't think of a better message */ - png_warning(png_ptr, "Invalid fcTL after IDAT skipped"); - png_crc_finish(png_ptr, length-4); - return; - } - else if (png_ptr->mode & PNG_HAVE_fcTL) - { - png_warning(png_ptr, "Duplicate fcTL within one frame skipped"); - png_crc_finish(png_ptr, length-4); - return; - } - else if (length != 26) - { - png_warning(png_ptr, "fcTL with invalid length skipped"); - png_crc_finish(png_ptr, length-4); - return; - } - - png_crc_read(png_ptr, data, 22); - png_crc_finish(png_ptr, 0); - - width = png_get_uint_31(png_ptr, data); - height = png_get_uint_31(png_ptr, data + 4); - x_offset = png_get_uint_31(png_ptr, data + 8); - y_offset = png_get_uint_31(png_ptr, data + 12); - delay_num = png_get_uint_16(data + 16); - delay_den = png_get_uint_16(data + 18); - dispose_op = data[20]; - blend_op = data[21]; - - if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0)) - { - png_warning(png_ptr, "fcTL for the first frame must have zero offset"); - return; - } - - if (info_ptr != NULL) - { - if (png_ptr->num_frames_read == 0 && - (width != info_ptr->width || height != info_ptr->height)) - { - png_warning(png_ptr, "size in first frame's fcTL must match " - "the size in IHDR"); - return; - } - - /* The set function will do more error checking */ - png_set_next_frame_fcTL(png_ptr, info_ptr, width, height, - x_offset, y_offset, delay_num, delay_den, - dispose_op, blend_op); - - png_read_reinit(png_ptr, info_ptr); - - png_ptr->mode |= PNG_HAVE_fcTL; - } -} - -void /* PRIVATE */ -png_have_info(png_structp png_ptr, png_infop info_ptr) -{ - if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL)) - { - png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN; - info_ptr->num_frames++; - } -} - -void /* PRIVATE */ -png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_ensure_sequence_number(png_ptr, length); - - /* This function is only called from png_read_end(), png_read_info(), - * and png_push_read_chunk() which means that: - * - the user doesn't want to read this frame - * - or this is an out-of-place fdAT - * in either case it is safe to ignore the chunk with a warning */ - png_warning(png_ptr, "ignoring fdAT chunk"); - png_crc_finish(png_ptr, length - 4); - PNG_UNUSED(info_ptr) -} - -void /* PRIVATE */ -png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length) -{ - png_byte data[4]; - png_uint_32 sequence_number; - - if (length < 4) - png_error(png_ptr, "invalid fcTL or fdAT chunk found"); - - png_crc_read(png_ptr, data, 4); - sequence_number = png_get_uint_31(png_ptr, data); - - if (sequence_number != png_ptr->next_seq_num) - png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence " - "number found"); - - png_ptr->next_seq_num++; -} -#endif /* PNG_READ_APNG_SUPPORTED */ - #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ static int @@ -4343,38 +4166,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, { uInt avail_in; png_bytep buffer; -#ifdef PNG_READ_APNG_SUPPORTED - png_uint_32 bytes_to_skip = 0; - - while (png_ptr->idat_size == 0 || bytes_to_skip != 0) - { - png_crc_finish(png_ptr, bytes_to_skip); - bytes_to_skip = 0; - - png_ptr->idat_size = png_read_chunk_header(png_ptr); - if (png_ptr->num_frames_read == 0) - { - if (png_ptr->chunk_name != png_IDAT) - png_error(png_ptr, "Not enough image data"); - } - else - { - if (png_ptr->chunk_name == png_IEND) - png_error(png_ptr, "Not enough image data"); - if (png_ptr->chunk_name != png_fdAT) - { - png_warning(png_ptr, "Skipped (ignored) a chunk " - "between APNG chunks"); - bytes_to_skip = png_ptr->idat_size; - continue; - } - - png_ensure_sequence_number(png_ptr, png_ptr->idat_size); - png_ptr->idat_size -= 4; - } - } -#else while (png_ptr->idat_size == 0) { png_crc_finish(png_ptr, 0); @@ -4386,7 +4178,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, if (png_ptr->chunk_name != png_IDAT) png_error(png_ptr, "Not enough image data"); } -#endif /* PNG_READ_APNG_SUPPORTED */ + avail_in = png_ptr->IDAT_read_size; if (avail_in > png_ptr->idat_size) @@ -4449,9 +4241,6 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; -#ifdef PNG_READ_APNG_SUPPORTED - png_ptr->num_frames_read++; -#endif if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) png_chunk_benign_error(png_ptr, "Extra compressed data"); @@ -4833,14 +4622,13 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) */ { png_bytep temp = png_ptr->big_row_buf + 32; - int extra = (int)((temp - (png_bytep)0) & 0x0f); + size_t extra = (size_t)temp & 0x0f; png_ptr->row_buf = temp - extra - 1/*filter byte*/; temp = png_ptr->big_prev_row + 32; - extra = (int)((temp - (png_bytep)0) & 0x0f); + extra = (size_t)temp & 0x0f; png_ptr->prev_row = temp - extra - 1/*filter byte*/; } - #else /* Use 31 bytes of padding before and 17 bytes after row_buf. */ png_ptr->row_buf = png_ptr->big_row_buf + 31; @@ -4890,80 +4678,4 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) png_ptr->flags |= PNG_FLAG_ROW_INIT; } - -#ifdef PNG_READ_APNG_SUPPORTED -/* This function is to be called after the main IDAT set has been read and - * before a new IDAT is read. It resets some parts of png_ptr - * to make them usable by the read functions again */ -void /* PRIVATE */ -png_read_reset(png_structp png_ptr) -{ - png_ptr->mode &= ~PNG_HAVE_IDAT; - png_ptr->mode &= ~PNG_AFTER_IDAT; - png_ptr->row_number = 0; - png_ptr->pass = 0; -} - -void /* PRIVATE */ -png_read_reinit(png_structp png_ptr, png_infop info_ptr) -{ - png_ptr->width = info_ptr->next_frame_width; - png_ptr->height = info_ptr->next_frame_height; - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width); - png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, - png_ptr->width); - if (png_ptr->prev_row) - memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); -} - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -/* same as png_read_reset() but for the progressive reader */ -void /* PRIVATE */ -png_progressive_read_reset(png_structp png_ptr) -{ -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; - - if (png_ptr->interlaced) - { - if (!(png_ptr->transformations & PNG_INTERLACE)) - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; - else - png_ptr->num_rows = png_ptr->height; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - } - else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - { - png_ptr->num_rows = png_ptr->height; - png_ptr->iwidth = png_ptr->width; - } - png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED; - if (inflateReset(&(png_ptr->zstream)) != Z_OK) - png_error(png_ptr, "inflateReset failed"); - png_ptr->zstream.avail_in = 0; - png_ptr->zstream.next_in = 0; - png_ptr->zstream.next_out = png_ptr->row_buf; - png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; -} -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ -#endif /* PNG_READ_APNG_SUPPORTED */ #endif /* READ */ diff --git a/thirdparty/libpng/pngset.c b/thirdparty/libpng/pngset.c index a281db58ae..8c372cf415 100644 --- a/thirdparty/libpng/pngset.c +++ b/thirdparty/libpng/pngset.c @@ -1,7 +1,7 @@ /* pngset.c - storage of image information into info struct * - * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -288,11 +288,6 @@ png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); - -#ifdef PNG_APNG_SUPPORTED - /* for non-animated png. this may be overwritten from an acTL chunk later */ - info_ptr->num_frames = 1; -#endif } #ifdef PNG_oFFs_SUPPORTED @@ -1024,6 +1019,9 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, info_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans); + + info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->free_me |= PNG_FREE_TRNS; } png_ptr->trans_alpha = info_ptr->trans_alpha; } @@ -1163,147 +1161,6 @@ png_set_sPLT(png_const_structrp png_ptr, } #endif /* sPLT */ -#ifdef PNG_APNG_SUPPORTED -png_uint_32 PNGAPI -png_set_acTL(png_structp png_ptr, png_infop info_ptr, - png_uint_32 num_frames, png_uint_32 num_plays) -{ - png_debug1(1, "in %s storage function", "acTL"); - - if (png_ptr == NULL || info_ptr == NULL) - { - png_warning(png_ptr, - "Call to png_set_acTL() with NULL png_ptr " - "or info_ptr ignored"); - return (0); - } - if (num_frames == 0) - { - png_warning(png_ptr, - "Ignoring attempt to set acTL with num_frames zero"); - return (0); - } - if (num_frames > PNG_UINT_31_MAX) - { - png_warning(png_ptr, - "Ignoring attempt to set acTL with num_frames > 2^31-1"); - return (0); - } - if (num_plays > PNG_UINT_31_MAX) - { - png_warning(png_ptr, - "Ignoring attempt to set acTL with num_plays " - "> 2^31-1"); - return (0); - } - - info_ptr->num_frames = num_frames; - info_ptr->num_plays = num_plays; - - info_ptr->valid |= PNG_INFO_acTL; - - return (1); -} - -/* delay_num and delay_den can hold any 16-bit values including zero */ -png_uint_32 PNGAPI -png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr, - png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, - png_byte dispose_op, png_byte blend_op) -{ - png_debug1(1, "in %s storage function", "fcTL"); - - if (png_ptr == NULL || info_ptr == NULL) - { - png_warning(png_ptr, - "Call to png_set_fcTL() with NULL png_ptr or info_ptr " - "ignored"); - return (0); - } - - png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset, - delay_num, delay_den, dispose_op, blend_op); - - if (blend_op == PNG_BLEND_OP_OVER) - { - if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) && - !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) - { - png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless " - "and wasteful for opaque images, ignored"); - blend_op = PNG_BLEND_OP_SOURCE; - } - } - - info_ptr->next_frame_width = width; - info_ptr->next_frame_height = height; - info_ptr->next_frame_x_offset = x_offset; - info_ptr->next_frame_y_offset = y_offset; - info_ptr->next_frame_delay_num = delay_num; - info_ptr->next_frame_delay_den = delay_den; - info_ptr->next_frame_dispose_op = dispose_op; - info_ptr->next_frame_blend_op = blend_op; - - info_ptr->valid |= PNG_INFO_fcTL; - - return (1); -} - -void /* PRIVATE */ -png_ensure_fcTL_is_valid(png_structp png_ptr, - png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, - png_byte dispose_op, png_byte blend_op) -{ - if (width == 0 || width > PNG_UINT_31_MAX) - png_error(png_ptr, "invalid width in fcTL (> 2^31-1)"); - if (height == 0 || height > PNG_UINT_31_MAX) - png_error(png_ptr, "invalid height in fcTL (> 2^31-1)"); - if (x_offset > PNG_UINT_31_MAX) - png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)"); - if (y_offset > PNG_UINT_31_MAX) - png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)"); - if (width + x_offset > png_ptr->first_frame_width || - height + y_offset > png_ptr->first_frame_height) - png_error(png_ptr, "dimensions of a frame are greater than" - "the ones in IHDR"); - - if (dispose_op != PNG_DISPOSE_OP_NONE && - dispose_op != PNG_DISPOSE_OP_BACKGROUND && - dispose_op != PNG_DISPOSE_OP_PREVIOUS) - png_error(png_ptr, "invalid dispose_op in fcTL"); - - if (blend_op != PNG_BLEND_OP_SOURCE && - blend_op != PNG_BLEND_OP_OVER) - png_error(png_ptr, "invalid blend_op in fcTL"); - - PNG_UNUSED(delay_num) - PNG_UNUSED(delay_den) -} - -png_uint_32 PNGAPI -png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr, - png_byte is_hidden) -{ - png_debug(1, "in png_first_frame_is_hidden()"); - - if (png_ptr == NULL) - return 0; - - if (is_hidden) - png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN; - else - png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN; - - PNG_UNUSED(info_ptr) - - return 1; -} -#endif /* PNG_APNG_SUPPORTED */ - #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED static png_byte check_location(png_const_structrp png_ptr, int location) @@ -1472,7 +1329,7 @@ png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI -png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) +png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features) { png_debug(1, "in png_permit_mng_features"); @@ -1779,7 +1636,7 @@ png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI -png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, +png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max) { /* Images with dimensions larger than these limits will be @@ -1795,7 +1652,7 @@ png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, /* This function was added to libpng 1.4.0 */ void PNGAPI -png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) +png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { if (png_ptr != NULL) png_ptr->user_chunk_cache_max = user_chunk_cache_max; @@ -1803,7 +1660,7 @@ png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) /* This function was added to libpng 1.4.1 */ void PNGAPI -png_set_chunk_malloc_max (png_structrp png_ptr, +png_set_chunk_malloc_max(png_structrp png_ptr, png_alloc_size_t user_chunk_malloc_max) { if (png_ptr != NULL) diff --git a/thirdparty/libpng/pngstruct.h b/thirdparty/libpng/pngstruct.h index 2a2236f92e..e591d94d58 100644 --- a/thirdparty/libpng/pngstruct.h +++ b/thirdparty/libpng/pngstruct.h @@ -1,7 +1,7 @@ /* pngstruct.h - header file for PNG reference library * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -334,18 +334,8 @@ struct png_struct_def size_t current_buffer_size; /* amount of data now in current_buffer */ int process_mode; /* what push library is currently doing */ int cur_palette; /* current push library palette index */ - #endif /* PROGRESSIVE_READ */ -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* For the Borland special 64K segment handler */ - png_bytepp offset_table_ptr; - png_bytep offset_table; - png_uint_16 offset_table_number; - png_uint_16 offset_table_count; - png_uint_16 offset_table_count_free; -#endif - #ifdef PNG_READ_QUANTIZE_SUPPORTED png_bytep palette_lookup; /* lookup table for quantizing */ png_bytep quantize_index; /* index translation for palette files */ @@ -409,27 +399,6 @@ struct png_struct_def png_byte filter_type; #endif -#ifdef PNG_APNG_SUPPORTED - png_uint_32 apng_flags; - png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */ - png_uint_32 first_frame_width; - png_uint_32 first_frame_height; - -#ifdef PNG_READ_APNG_SUPPORTED - png_uint_32 num_frames_read; /* incremented after all image data of */ - /* a frame is read */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_frame_ptr frame_info_fn; /* frame info read callback */ - png_progressive_frame_ptr frame_end_fn; /* frame data read callback */ -#endif -#endif - -#ifdef PNG_WRITE_APNG_SUPPORTED - png_uint_32 num_frames_to_write; - png_uint_32 num_frames_written; -#endif -#endif /* PNG_APNG_SUPPORTED */ - /* New members added in libpng-1.2.0 */ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c index 5e68032378..06c45d16ab 100644 --- a/thirdparty/libpng/pngwrite.c +++ b/thirdparty/libpng/pngwrite.c @@ -1,7 +1,7 @@ /* pngwrite.c - general routines to write a PNG file * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -128,10 +128,6 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) * the application continues writing the PNG. So check the 'invalid' * flag here too. */ -#ifdef PNG_WRITE_APNG_SUPPORTED - if (info_ptr->valid & PNG_INFO_acTL) - png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays); -#endif #ifdef PNG_GAMMA_SUPPORTED # ifdef PNG_WRITE_gAMA_SUPPORTED if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && @@ -374,11 +370,6 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); #endif -#ifdef PNG_WRITE_APNG_SUPPORTED - if (png_ptr->num_frames_written != png_ptr->num_frames_to_write) - png_error(png_ptr, "Not enough frames written"); -#endif - /* See if user wants us to write information chunks */ if (info_ptr != NULL) { @@ -498,6 +489,16 @@ png_convert_from_time_t(png_timep ptime, time_t ttime) png_debug(1, "in png_convert_from_time_t"); tbuf = gmtime(&ttime); + if (tbuf == NULL) + { + /* TODO: add a safe function which takes a png_ptr argument and raises + * a png_error if the ttime argument is invalid and the call to gmtime + * fails as a consequence. + */ + memset(ptime, 0, sizeof(*ptime)); + return; + } + png_convert_from_struct_tm(ptime, tbuf); } #endif @@ -1470,43 +1471,6 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr, } #endif -#ifdef PNG_WRITE_APNG_SUPPORTED -void PNGAPI -png_write_frame_head(png_structp png_ptr, png_infop info_ptr, - png_bytepp row_pointers, png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, - png_byte blend_op) -{ - png_debug(1, "in png_write_frame_head"); - - /* there is a chance this has been set after png_write_info was called, - * so it would be set but not written. is there a way to be sure? */ - if (!(info_ptr->valid & PNG_INFO_acTL)) - png_error(png_ptr, "png_write_frame_head(): acTL not set"); - - png_write_reset(png_ptr); - - png_write_reinit(png_ptr, info_ptr, width, height); - - if ( !(png_ptr->num_frames_written == 0 && - (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) ) - png_write_fcTL(png_ptr, width, height, x_offset, y_offset, - delay_num, delay_den, dispose_op, blend_op); - - PNG_UNUSED(row_pointers) -} - -void PNGAPI -png_write_frame_tail(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_write_frame_tail"); - - png_ptr->num_frames_written++; - - PNG_UNUSED(info_ptr) -} -#endif /* PNG_WRITE_APNG_SUPPORTED */ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED /* Initialize the write structure - general purpose utility. */ diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c index b4809cda6b..16345e4c0b 100644 --- a/thirdparty/libpng/pngwutil.c +++ b/thirdparty/libpng/pngwutil.c @@ -821,11 +821,6 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, /* Write the chunk */ png_write_complete_chunk(png_ptr, png_IHDR, buf, 13); -#ifdef PNG_WRITE_APNG_SUPPORTED - png_ptr->first_frame_width = width; - png_ptr->first_frame_height = height; -#endif - if ((png_ptr->do_filter) == PNG_NO_FILTERS) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || @@ -1007,17 +1002,8 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, optimize_cmf(data, png_image_size(png_ptr)); #endif - if (size > 0) -#ifdef PNG_WRITE_APNG_SUPPORTED - { - if (png_ptr->num_frames_written == 0) -#endif - png_write_complete_chunk(png_ptr, png_IDAT, data, size); -#ifdef PNG_WRITE_APNG_SUPPORTED - else - png_write_fdAT(png_ptr, data, size); - } -#endif /* PNG_WRITE_APNG_SUPPORTED */ + if (size > 0) + png_write_complete_chunk(png_ptr, png_IDAT, data, size); png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->zstream.next_out = data; @@ -1064,17 +1050,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, #endif if (size > 0) -#ifdef PNG_WRITE_APNG_SUPPORTED - { - if (png_ptr->num_frames_written == 0) -#endif png_write_complete_chunk(png_ptr, png_IDAT, data, size); -#ifdef PNG_WRITE_APNG_SUPPORTED - else - png_write_fdAT(png_ptr, data, size); - } -#endif /* PNG_WRITE_APNG_SUPPORTED */ - png_ptr->zstream.avail_out = 0; png_ptr->zstream.next_out = NULL; png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; @@ -1909,82 +1885,6 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) } #endif -#ifdef PNG_WRITE_APNG_SUPPORTED -void /* PRIVATE */ -png_write_acTL(png_structp png_ptr, - png_uint_32 num_frames, png_uint_32 num_plays) -{ - png_byte buf[8]; - - png_debug(1, "in png_write_acTL"); - - png_ptr->num_frames_to_write = num_frames; - - if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) - num_frames--; - - png_save_uint_32(buf, num_frames); - png_save_uint_32(buf + 4, num_plays); - - png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8); -} - -void /* PRIVATE */ -png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height, - png_uint_32 x_offset, png_uint_32 y_offset, - png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, - png_byte blend_op) -{ - png_byte buf[26]; - - png_debug(1, "in png_write_fcTL"); - - if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0)) - png_error(png_ptr, "x and/or y offset for the first frame aren't 0"); - if (png_ptr->num_frames_written == 0 && - (width != png_ptr->first_frame_width || - height != png_ptr->first_frame_height)) - png_error(png_ptr, "width and/or height in the first frame's fcTL " - "don't match the ones in IHDR"); - - /* more error checking */ - png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset, - delay_num, delay_den, dispose_op, blend_op); - - png_save_uint_32(buf, png_ptr->next_seq_num); - png_save_uint_32(buf + 4, width); - png_save_uint_32(buf + 8, height); - png_save_uint_32(buf + 12, x_offset); - png_save_uint_32(buf + 16, y_offset); - png_save_uint_16(buf + 20, delay_num); - png_save_uint_16(buf + 22, delay_den); - buf[24] = dispose_op; - buf[25] = blend_op; - - png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26); - - png_ptr->next_seq_num++; -} - -void /* PRIVATE */ -png_write_fdAT(png_structp png_ptr, - png_const_bytep data, png_size_t length) -{ - png_byte buf[4]; - - png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length)); - - png_save_uint_32(buf, png_ptr->next_seq_num); - png_write_chunk_data(png_ptr, buf, 4); - - png_write_chunk_data(png_ptr, data, length); - - png_write_chunk_end(png_ptr); - - png_ptr->next_seq_num++; -} -#endif /* PNG_WRITE_APNG_SUPPORTED */ - /* Initializes the row writing capability of libpng */ void /* PRIVATE */ png_write_start_row(png_structrp png_ptr) @@ -2878,39 +2778,4 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, } #endif /* WRITE_FLUSH */ } - -#ifdef PNG_WRITE_APNG_SUPPORTED -void /* PRIVATE */ -png_write_reset(png_structp png_ptr) -{ - png_ptr->row_number = 0; - png_ptr->pass = 0; - png_ptr->mode &= ~PNG_HAVE_IDAT; -} - -void /* PRIVATE */ -png_write_reinit(png_structp png_ptr, png_infop info_ptr, - png_uint_32 width, png_uint_32 height) -{ - if (png_ptr->num_frames_written == 0 && - (width != png_ptr->first_frame_width || - height != png_ptr->first_frame_height)) - png_error(png_ptr, "width and/or height in the first frame's fcTL " - "don't match the ones in IHDR"); - if (width > png_ptr->first_frame_width || - height > png_ptr->first_frame_height) - png_error(png_ptr, "width and/or height for a frame greater than" - "the ones in IHDR"); - - png_set_IHDR(png_ptr, info_ptr, width, height, - info_ptr->bit_depth, info_ptr->color_type, - info_ptr->interlace_type, info_ptr->compression_type, - info_ptr->filter_type); - - png_ptr->width = width; - png_ptr->height = height; - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); - png_ptr->usr_width = png_ptr->width; -} -#endif /* PNG_WRITE_APNG_SUPPORTED */ #endif /* WRITE */ |